home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / os20 / util / hackdisk202.lha / hackdisk.s < prev    next >
Text File  |  1993-04-04  |  70KB  |  3,030 lines

  1. ********************************************************************************
  2. * hackdisk.s -- my very own version of trackdisk.device
  3. * Copyright © 1992,93 by Dan Babcock
  4. *
  5. * Version history:
  6. * V1.00 04/25/92 First version. Supports 880K drives only.
  7. * V1.01 04/28/92 Optimized CopyMem
  8. * V1.02 04/30/92 More intelligent write algorithm fixes performance problem
  9. * V1.03 05/03/92 Sets IO_ACTUAL
  10. * V1.04 06/24/92 Fixes a couple bugs: RemChangeInt works now, and disk change
  11. *                errors are only reported when it makes sense.
  12. *                CrossDOSV5/CrossPC flushed out these bugs.
  13. * V1.10 07/04/92 Compatible with Kickstart 1.2 and higher.
  14. *                Fixed Seek (IO_OFFSET is in bytes, not tracks).
  15. *                Released on Fish 697.
  16. * V1.11 08/03/92 Fixed bug in readtrack routine - buffer not cleared if error
  17. *                in some cases (no sync).
  18. *                Fills TC_Userdata with bogus value to fool CrossDOS under Kick
  19. *                1.2/1.3.
  20. *                Puts -1 in IO_DEVICE on open error. Some (though not many)
  21. *                applications depend on this.
  22. *                Using a slightly more creative "invalid sync word" (was 0).
  23. *                This should fix many drive incompatibility problems.
  24. *                Glitch in disk check code fixed (only affected non-NoClick mode).
  25. * V1.12 08/16/92 CMD_STOP/CMD_START should work now.
  26. * V2.00 12/26/92 Supports Chinon/Commodore FB357A 150RPM HD floppy drives.
  27. *                Support added for 5.25 inch drives (NOT TESTED!!!)
  28. *                Added track number to verify error display (only under 2.0+).
  29. *                Added a tiny module at the end (see the comments for details).
  30. *                Released on Fish 803.
  31. * V2.01 01/22/93 Bug fix: write protection detected (broke in 2.00)
  32. * V2.02 03/13/93 Now performs an AllocUnit on all units in the initroutine
  33. ********************************************************************************
  34.  
  35. ;This source was assembled with Macro68 release 3.
  36.  
  37.     exeobj
  38.     objfile    'devs:hackdisk.device'
  39.     MC68000
  40.     multipass
  41.  
  42. ;Standard register usage:
  43. ;A6            - ExecBase or $dff000
  44. ;A5 (A_DEVICE) - device ptr
  45. ;A4 (A_UNIT)   - unit ptr
  46. ;A3 (A_IO)     - IORequest
  47.  
  48.     IFND    SYS
  49. SYS    macro
  50.     jsr    _LVO\1(a6)
  51.     endm
  52.     ENDC
  53.  
  54.     IFND    _custom
  55. _custom    equ    $dff000
  56.     ENDC
  57.  
  58. ;Set INFO_LEVEL to 1 for full debugging output over the internal serial port.
  59. INFO_LEVEL    equ    0
  60.  
  61. A_DEVICE    equr    a5
  62. A_UNIT    equr    a4
  63. A_IO    equr    a3
  64.  
  65.  
  66. VERSION    equ    127
  67. REVISION    equ    0
  68. MYPRI    equ    0
  69.  
  70. MD_NUMUNITS    equ    4
  71. STACKSIZE    equ    4000
  72. TASKPRI    equ    5
  73.  
  74. RETRYCNT    equ    3
  75.  
  76. ;Put a message to the serial port.  Used like so:
  77. ;
  78. ;PUTDEBUG    <'Init: called'>
  79. ;
  80. ;Parameters can be printed out by pushing them on the stack and
  81. ;adding the appropriate C printf-style % formatting commands.
  82.  
  83. PUTDEBUG     macro    ;<msg>
  84.     ifne    INFO_LEVEL
  85.     movem.l    d0-d1/a0-a1,-(sp)
  86.     lea    .msg\@(pc),a0    ;Point to static format string
  87.     lea    16(sp),a1    ;Point to args
  88.     bsr    KPutFmt
  89.     movem.l    (sp)+,d0-d1/a0-a1
  90.     bra    .end\@
  91. .msg\@:
  92.     dc.b    \1,$a,0
  93.     even
  94. .end\@:
  95.     endc
  96.     endm
  97.  
  98. *--------------------------------------------------------------------
  99. *
  100. * Driver error defines
  101. *
  102. *--------------------------------------------------------------------
  103.  
  104. ;TDERR_NotSpecified    EQU    20    ; general catchall
  105. ;TDERR_NoSecHdr        EQU    21    ; couldn't even find a sector
  106. ;TDERR_BadSecPreamble    EQU    22    ; sector looked wrong
  107. ;TDERR_BadSecID        EQU    23    ; ditto
  108. ;TDERR_BadHdrSum        EQU    24    ; header had incorrect checksum
  109. ;TDERR_BadSecSum        EQU    25    ; data had incorrect checksum
  110. ;TDERR_TooFewSecs    EQU    26    ; couldn't find enough sectors
  111. ;TDERR_BadSecHdr        EQU    27    ; another "sector looked wrong"
  112. ;TDERR_WriteProt        EQU    28    ; can't write to a protected disk
  113. ;TDERR_DiskChanged    EQU    29    ; no disk in the drive
  114. ;TDERR_SeekError        EQU    30    ; couldn't find track 0
  115. ;TDERR_NoMem        EQU    31    ; ran out of memory
  116. ;TDERR_BadUnitNum    EQU    32    ; asked for a unit > NUMUNITS
  117. ;TDERR_BadDriveType    EQU    33    ; not a drive that trackdisk groks
  118. ;TDERR_DriveInUse    EQU    34    ; someone else allocated the drive
  119. ;TDERR_PostReset        EQU    35    ; user hit reset; awaiting doom
  120.  
  121. ; STRUCTURE TIMEVAL,0
  122. ;    ULONG    TV_SECS
  123. ;    ULONG    TV_MICRO
  124. ;    LABEL    TV_SIZE
  125.  
  126. ;Unit structure
  127.  
  128. *--------------------------------------------------------------------
  129. *
  130. * Public portion of unit structure
  131. *
  132. *--------------------------------------------------------------------
  133.  
  134. ;*------ UNIT_FLAG definitions:
  135.  
  136. ;These are bogus, but I won't re-define them.
  137. ;    BITDEF  UNIT,ACTIVE,0        ; driver is active
  138. ;    BITDEF  UNIT,INTASK,1        ; running in driver's task
  139.     BITDEF    UNIT,DiskInDrive,2
  140.     BITDEF    UNIT,WriteProtected,3
  141.  
  142. ; STRUCTURE TDU_PUBLICUNIT,UNIT_SIZE
  143. ;    UWORD    TDU_COMP01TRACK        ; track for first precomp
  144. ;    UWORD    TDU_COMP10TRACK        ; track for second precomp
  145. ;    UWORD    TDU_COMP11TRACK        ; track for third precomp
  146. ;    ULONG    TDU_STEPDELAY        ; time to wait after stepping
  147. ;    ULONG    TDU_SETTLEDELAY        ; time to wait after seeking
  148. ;    UBYTE    TDU_RETRYCNT        ; # of times to retry
  149. ;    UBYTE    TDU_PUBFLAGS        ; public flags, see below
  150. ;    UWORD    TDU_CURRTRK        ; track heads are over
  151.                     ;  (ONLY ACCESS WHILE UNIT IS STOPPED!)
  152. ;    ULONG    TDU_CALIBRATEDELAY    ; time to wait after stepping
  153.                     ; for recalibrate
  154. ;    ULONG    TDU_COUNTER        ; counter for disk changes
  155.                     ;  (ONLY ACCESS WHILE UNIT IS STOPPED!)
  156. ;    LABEL    TDU_PUBLICUNITSIZE
  157. ;*--------------------------------------------------------------------
  158.  
  159.     STRUCTURE    MyUnit,TDU_PUBLICUNITSIZE
  160.     STRUCT    Drive_LastCheck,TV_SIZE    ;last time diskchange was checked
  161.     STRUCT    ChangeIntList,MLH_SIZE    ;must be initialized!!!
  162.     LONG    TDRemoveInt
  163.     BYTE    UnitNum
  164.     BYTE    unit_pad1
  165.  
  166. ;The following will be InitStruct'ed in GetDriveType
  167.     LABEL    DriveParams
  168.     BYTE    DriveType
  169.     BYTE    NumTracks
  170.     LONG    BytesPerDisk
  171.     LONG    SectorMask
  172.     WORD    GapCount
  173.     LONG    SectorsPerTrack
  174.     LONG    RawBufSize
  175.     WORD    WriteDskLen
  176.     WORD    ReadDskLen
  177.     WORD    VerifyDskLen
  178.     WORD    MaxValidSec
  179.     WORD    FirstSector
  180.     LABEL    EndDriveParams
  181. ;MUST be word-aligned!!!
  182.     LABEL    MyUnit_Sizeof
  183.  
  184. DriveParams_Sizeof    equ    EndDriveParams-DriveParams
  185.  
  186.  
  187. ;*
  188. ;* Flags for TDU_PUBFLAGS:
  189. ;*
  190. ;    BITDEF    TDP,NOCLICK,0        ; set to enable noclickstart
  191.     BITDEF    TDP,VERIFY,1
  192.  
  193. ;Device global structure -- accessed as positive offsets from device base
  194. ;Note: The stuff in LIB_SIZE is *required*. Anything else is up to you...
  195.     STRUCTURE    DeviceGlobals,LIB_SIZE
  196.     STRUCT    TaskPort,MP_SIZE    ;MsgPort for task
  197.     STRUCT    Task,TC_SIZE
  198.     STRUCT    TaskStack,STACKSIZE
  199.     STRUCT    TempTimeVal,TV_SIZE
  200.     LONG    SegList    ;not used for ROM version
  201.     STRUCT    TimerIORequest,IOTV_SIZE
  202.     STRUCT    TimerPort,MP_SIZE
  203.     STRUCT    LastCheck,TV_SIZE    ;last time diskchange was checked
  204.     STRUCT    DiskResourceUnit,DRU_SIZE    ;must be initialized!!!
  205.     STRUCT    DiskResourcePort,MP_SIZE    ;must be initialized!!!
  206.  
  207. ;Allocated memory pointers
  208.     LONG    RawBuffer
  209.     LONG    DecodedBuffer
  210.     LONG    VerifyBuffer
  211.  
  212.     STRUCT    SectorLabels,22*16
  213.     STRUCT    Unit0,MyUnit_Sizeof
  214.     STRUCT    Unit1,MyUnit_Sizeof
  215.     STRUCT    Unit2,MyUnit_Sizeof
  216.     STRUCT    Unit3,MyUnit_Sizeof
  217.     LONG    GraphBase
  218.     LONG    IntBase
  219.     LONG    DiskResourceBase
  220.     LONG    CIABase
  221.     WORD    SyncCount
  222.     WORD    IndexDskLen
  223.     WORD    BlockIntDskLen
  224.     LONG    WriteMap
  225.  
  226.     LABEL    StartSigs
  227.     LONG    SyncSig
  228.     LONG    BlockSig
  229.     LABEL    EndSigs
  230.  
  231.     BYTE    BufferTrack
  232.     BYTE    BufferDrive
  233.     BYTE    DEV_FLAGS
  234.     BYTE    MotorState
  235.     BYTE    InquireBits
  236.     LABEL    MyDev_Sizeof
  237.  
  238. NumSigs    equ    (EndSigs-StartSigs)/4
  239.  
  240. ;Bit definitions for DEV_FLAGS:
  241.     BITDEF    DEV,Dirty,0    ;buffered track has been changed
  242.     BITDEF    DEV,Stopped,1    ;device is stopped
  243.     BITDEF    DEV,Verify,2    ;used by BlockInt for verify
  244.  
  245. ;A romtag structure.  After your driver is brought in from disk, the
  246. ;disk image will be scanned for this structure to discover magic constants
  247. ;about you (such as where to start running you from...).
  248.  
  249. RomTag:
  250.     dc.w    RTC_MATCHWORD    ;$4AFC ('illegal' opcode)
  251.     dc.l    RomTag
  252.     dc.l    EndCode    ;pointer to end of code
  253.     dc.b    RTF_AUTOINIT+RTF_COLDSTART    ;set things up automatically
  254.     dc.b    VERSION
  255.     dc.b    NT_DEVICE    ;module type (either device or library)
  256.     dc.b    MYPRI    ;usually not important
  257.     dc.l    Name    ;name used in OpenDevice
  258.     dc.l    IDString    ;optional
  259.     dc.l    Init    ;more init info
  260.  
  261. Name:    dc.b    'trackdisk.device',0
  262.     even
  263.  
  264. IDString:    dc.b    'Hackdisk V2.02 - Copyright © 1992,93 by Dan Babcock',$a,0
  265.     even
  266. DiskResourceName:
  267.     dc.b    'disk.resource',0
  268. TimerName:
  269.     dc.b    'timer.device',0
  270. GraphName:
  271.     dc.b    'graphics.library',0
  272. CIAName:    dc.b    'ciab.resource',0
  273. IntName:    dc.b    'intuition.library',0
  274.     even
  275.  
  276. ;The romtag specified that we were "RTF_AUTOINIT".  This means that the
  277. ;RT_INIT structure member points to one of these tables below.  If the
  278. ;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
  279.  
  280. Init:    dc.l    MyDev_Sizeof    ;data space size (at least
  281.                 ;LIB_SIZE!!)
  282.     dc.l    FuncTable    ;pointer to function initializers
  283.     dc.l    DataTable    ;pointer to data initializers
  284.     dc.l    InitRoutine    ;routine to run
  285.  
  286. FuncTable:
  287.     dc.w    -1    ;this indicates that the following are offsets,
  288.             ;rather than absolute addresses
  289.     dc.w    Open-FuncTable    ;standard system routines
  290.     dc.w    _Close-FuncTable
  291.     dc.w    Expunge-FuncTable
  292.     dc.w    .Null-FuncTable    ;Reserved for future use!
  293.     dc.w    BeginIO-FuncTable    ;device definitions
  294.     dc.w    AbortIO-FuncTable
  295.     dc.w    -1    ;function table end marker
  296. .Null:    moveq    #0,d0
  297.     rts
  298.  
  299. ;The data table initializes static data structures. The format is
  300. ;specified in exec/InitStruct routine's manual pages.  The
  301. ;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
  302. ;The first argument is the offset from the device base for this
  303. ;byte/word/long. The second argument is the value to put in that cell.
  304. ;The table is null terminated
  305.  
  306. DataTable:
  307.     INITBYTE    LN_TYPE,NT_DEVICE
  308.     INITLONG    LN_NAME,Name
  309.     INITBYTE    LIB_FLAGS,LIBF_SUMUSED+LIBF_CHANGED
  310.     INITWORD    LIB_VERSION,VERSION
  311.     INITWORD    LIB_REVISION,REVISION
  312.     INITLONG    LIB_IDSTRING,IDString
  313.     dc.w    0    ;terminate list (only one byte needed)
  314.  
  315. CmdTable:    dc.w    Invalid-CmdTable        ;0    CMD_INVALID
  316.     dc.w    Invalid-CmdTable        ;1    CMD_RESET
  317.     dc.w    Read-CmdTable        ;2    CMD_READ
  318.     dc.w    Write-CmdTable        ;3    CMD_WRITE / ETD_
  319.     dc.w    Update-CmdTable        ;4    CMD_UPDATE / ETD_
  320.     dc.w    Clear-CmdTable        ;5    CMD_CLEAR / ETD_
  321.     dc.w    MyStop-CmdTable        ;6    CMD_STOP / ETD_
  322.     dc.w    Start-CmdTable        ;7    CMD_START
  323.     dc.w    Invalid-CmdTable        ;8    CMD_FLUSH
  324.     dc.w    Motor-CmdTable        ;9    TD_MOTOR / ETD_
  325.     dc.w    TDSeek-CmdTable        ;10    TD_SEEK / ETD_
  326.     dc.w    Format-CmdTable        ;11    TD_FORMAT
  327.     dc.w    TDRemove-CmdTable        ;12    TD_REMOVE
  328.     dc.w    ChangeNum-CmdTable        ;13    TD_CHANGENUM
  329.     dc.w    ChangeState-CmdTable    ;14    TD_CHANGESTATE
  330.     dc.w    ProtStatus-CmdTable        ;15    TD_PROTSTATUS
  331.     dc.w    TDRawRead-CmdTable        ;16    TD_RAWREAD
  332.     dc.w    RawWrite-CmdTable        ;17    TD_RAWWRITE
  333.     dc.w    TDGetDriveType-CmdTable    ;18    TD_GETDRIVETYPE
  334.     dc.w    GetNumTracks-CmdTable    ;19    TD_GETNUMTRACKS
  335.     dc.w    AddChangeInt-CmdTable    ;20    TD_ADDCHANGEINT
  336.     dc.w    RemChangeInt-CmdTable    ;21    TD_REMCHANGEINT
  337.     dc.w    GetGeometry-CmdTable    ;22    TD_GETGEOMETRY
  338.     dc.w    Invalid-CmdTable        ;23    TD_EJECT
  339. EndCmdTable:
  340. HighestCommand    equ    ((EndCmdTable-CmdTable)/2)-1
  341. Invalid:    move.b    #IOERR_NOCMD,IO_ERROR(A_IO)
  342.     rts
  343.  
  344. InitRoutine:
  345. ;A0 - segment
  346. ;D0 - device ptr
  347.  
  348. ;Returns with the device ptr still in D0 if successful, otherwise zero.
  349.  
  350.     PUTDEBUG    <'InitRoutine: Entered'>
  351.     movem.l    d1-d7/a0-a6,-(sp)
  352.     move.l    d0,A_DEVICE
  353.     move.l    a0,SegList(A_DEVICE)
  354.     move.l    4,a6
  355.  
  356. ;Initialize ports
  357.     lea    TaskPort(A_DEVICE),a0
  358.     bsr    InitPort
  359.     lea    TimerPort(A_DEVICE),a0
  360.     bsr    InitPort
  361.  
  362. ;Invalidate track buffer
  363.     bsr    Clear
  364.  
  365. ;Open libraries/resources
  366.  
  367.     lea    DiskResourceName(pc),a1    ;'disk.resource'
  368.     SYS    OpenResource
  369.     move.l    d0,DiskResourceBase(A_DEVICE)
  370.     beq    .Failed
  371.  
  372. ;Try to allocate all the units.
  373.     move.l    d0,a6
  374.     moveq    #0,d2
  375. .AllocDisk:
  376.     move.l    d2,d0
  377.     IFND    _LVOAllocUnit
  378. _LVOAllocUnit    equ    -6
  379.     ENDC
  380.     SYS    AllocUnit
  381.     addq.l    #1,d2
  382.     cmp.w    #4,d2
  383.     blo    .AllocDisk
  384.     move.l    4,a6
  385.  
  386.     lea    CIAName(pc),a1    ;'ciab.resource'
  387.     SYS    OpenResource
  388.     move.l    d0,CIABase(A_DEVICE)
  389.     beq    .Failed
  390.  
  391.     lea    GraphName(pc),a1
  392.     SYS    OldOpenLibrary
  393.     move.l    d0,GraphBase(A_DEVICE)
  394.     beq    .Failed
  395.     lea    IntName(pc),a1
  396.     SYS    OldOpenLibrary
  397.     move.l    d0,IntBase(A_DEVICE)
  398.     beq    .Failed
  399.  
  400. ;Allocate buffer memory.
  401.     move.l    #DISK_RawBufSize*2,d0
  402.     move.l    #MEMF_CHIP,d1
  403.     SYS    AllocMem
  404.     move.l    d0,RawBuffer(A_DEVICE)
  405.     beq    .Failed
  406.  
  407.     move.l    #512*22,d0
  408.     move.l    #MEMF_CHIP,d1
  409.     SYS    AllocMem
  410.     move.l    d0,DecodedBuffer(A_DEVICE)
  411.     beq    .Failed
  412.  
  413.     move.l    #(1088*22)+2,d0
  414.     move.l    #MEMF_CHIP,d1
  415.     SYS    AllocMem
  416.     move.l    d0,VerifyBuffer(A_DEVICE)
  417.     beq    .Failed
  418.  
  419. ;Set up disk.resource structure.
  420.     lea    DiskResourcePort(A_DEVICE),a0
  421.     bsr    InitPort
  422.     move.l    a0,DiskResourceUnit+MN_REPLYPORT(A_DEVICE)
  423. ;    move.b    #PA_SIGNAL,MP_FLAGS(a0)    ;not needed (0)
  424.     lea    Name(pc),a0
  425.     move.l    a0,DiskResourceUnit+LN_NAME(A_DEVICE)
  426.  
  427.     move.l    A_DEVICE,DiskResourceUnit+DRU_DISCBLOCK+IS_DATA(A_DEVICE)
  428.     move.l    A_DEVICE,DiskResourceUnit+DRU_DISCSYNC+IS_DATA(A_DEVICE)
  429.     move.l    A_DEVICE,DiskResourceUnit+DRU_INDEX+IS_DATA(A_DEVICE)
  430.     lea    BlockInt(pc),a0
  431.     move.l    a0,DiskResourceUnit+DRU_DISCBLOCK+IS_CODE(A_DEVICE)
  432.     lea    SyncInt(pc),a0
  433.     move.l    a0,DiskResourceUnit+DRU_DISCSYNC+IS_CODE(A_DEVICE)
  434.     lea    IndexInt(pc),a0
  435.     move.l    a0,DiskResourceUnit+DRU_INDEX+IS_CODE(A_DEVICE)
  436.     moveq    #NT_INTERRUPT,d0
  437.     move.b    d0,DiskResourceUnit+DRU_DISCBLOCK+LN_TYPE(A_DEVICE)
  438.     move.b    d0,DiskResourceUnit+DRU_DISCSYNC+LN_TYPE(A_DEVICE)
  439.     move.b    d0,DiskResourceUnit+DRU_INDEX+LN_TYPE(A_DEVICE)
  440.  
  441. ;Initialize timer IORequest (except signal)
  442.     lea    TimerPort(A_DEVICE),a0
  443. ;    move.b    #PA_SIGNAL,MP_FLAGS(a0)    ;not needed (0)
  444.     move.l    a0,TimerIORequest+MN_REPLYPORT(A_DEVICE)
  445.     lea    TimerName(pc),a0
  446.     moveq    #UNIT_MICROHZ,d0
  447.     lea    TimerIORequest(A_DEVICE),a1
  448.     moveq    #0,d1
  449.     SYS    OpenDevice
  450.     tst.l    d0
  451.     bne    .Failed
  452.  
  453. ;*** Set up unit structures
  454.     moveq    #0,d2
  455.     lea    Unit0(A_DEVICE),A_UNIT
  456. .UnitLoop:
  457.     move.b    d2,UnitNum(A_UNIT)
  458.     lea    ChangeIntList(A_UNIT),a0
  459.     NEWLIST    a0
  460.     bset    #1,TDU_PUBFLAGS(A_UNIT)    ;verify ON!
  461.     move.b    #RETRYCNT,TDU_RETRYCNT(A_UNIT)
  462.     lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  463.     addq.b    #1,d2
  464.     cmp.b    #MD_NUMUNITS,d2
  465.     blo    .UnitLoop
  466.  
  467. ;Set up task
  468.     move.b    #PA_IGNORE,TaskPort+MP_FLAGS(A_DEVICE)
  469.     move.b    #NT_MSGPORT,TaskPort+LN_TYPE(A_DEVICE)
  470.     lea    Task(A_DEVICE),a1    ;Task Control Block
  471.  
  472. ;To make CrossDOS happy under 1.2/1.3
  473.     st    TC_Userdata(a1)
  474.  
  475.     lea    Name(pc),a0
  476.     move.l    a0,LN_NAME(a1)
  477.     move.b    #TASKPRI,LN_PRI(a1)
  478.     move.b    #NT_TASK,LN_TYPE(a1)
  479.     lea    TaskCode(pc),a2    ;initial PC
  480.     sub.l    a3,a3    ;final PC
  481.     lea    TaskStack(A_DEVICE),a0
  482.     move.l    a0,TC_SPLOWER(a1)
  483.     lea    STACKSIZE(a0),a0
  484.     move.l    a0,TC_SPUPPER(a1)
  485.  
  486.     move.l    A_DEVICE,-(a0)    ;pass device pointer to task
  487.     move.l    a0,TC_SPREG(a1)
  488.     move.l    a1,TaskPort+MP_SIGTASK(A_DEVICE)
  489.     SYS    AddTask
  490.  
  491.     move.l    A_DEVICE,d0
  492.     PUTDEBUG    <'InitRoutine: Done'>
  493. .End:    movem.l    (sp)+,d1-d7/a0-a6
  494.     rts
  495. .Failed:
  496.     PUTDEBUG    <'InitRoutine: Failed'>
  497. ;    bsr    CloseEverything
  498.     moveq    #0,d0
  499.     bra    .End
  500.  
  501. InitPort:
  502. ;Enter with pointer to port in A0. All registers preserved.
  503.     push    a0
  504.     lea    MP_MSGLIST(a0),a0
  505.     NEWLIST    a0
  506.     pop    a0
  507.     rts
  508.  
  509.     comment |
  510. CloseEverything:
  511. ;This routines cleans up device stuff. Enter with A_DEVICE.
  512.  
  513.     movem.l    d0-d1/a0-a1/a6,-(sp)
  514.     move.l    4,a6
  515. ;Close timer
  516.     tst.b    TimerIORequest+IO_ERROR(A_DEVICE)
  517.     beq    .SkipTimer
  518.     lea    TimerIORequest(A_DEVICE),a1
  519.     SYS    CloseDevice
  520. .SkipTimer:
  521.  
  522. ;Remove task
  523.     lea    Name(pc),a1
  524.     SYS    FindTask
  525.     tst.l    d0
  526.     beq    .SkipTask
  527.     move.l    d0,a1
  528.     SYS    RemTask
  529. .SkipTask:
  530.  
  531. ;Close libraries
  532.     move.l    GraphBase(A_DEVICE),d0
  533.     beq    .SkipGfx
  534.     move.l    d0,a1
  535.     SYS    CloseLibrary
  536. .SkipGfx:
  537.     move.l    IntBase(A_DEVICE),d0
  538.     beq    .SkipInt
  539.     move.l    d0,a1
  540.     SYS    CloseLibrary
  541. .SkipInt:
  542.  
  543. ;Free CHIP RAM. (Note: This will change when I support other drive types).
  544.     move.l    RawBuffer(A_DEVICE),d0
  545.     beq    .SkipRaw
  546.     move.l    d0,a1
  547.     move.l    #DISK_RawBufSize,d0
  548.     SYS    FreeMem
  549. .SkipRaw:
  550.     move.l    DecodedBuffer(A_DEVICE),d0
  551.     beq    .SkipDecoded
  552.     move.l    d0,a1
  553.     move.l    #512*11,d0
  554.     SYS    FreeMem
  555. .SkipDecoded:
  556.     move.l    VerifyBuffer(A_DEVICE),d0
  557.     beq    .SkipVerify
  558.     move.l    d0,a1
  559.     move.l    #(1088*11)+2,d0
  560.     SYS    FreeMem
  561. .SkipVerify:
  562. .End:    movem.l    (sp)+,d0-d1/a0-a1/a6
  563.     rts
  564. |
  565.  
  566. ;******************************* Task code ******************************
  567.  
  568. TaskCode:
  569.     PUTDEBUG    <'Task: Entered'>
  570.     move.l    4,a6
  571.  
  572. ;Grab the arguments passed down from our parent
  573.     move.l    4(sp),A_DEVICE    ;Device pointer
  574.  
  575. ;General initialization
  576.  
  577.     lea    StartSigs(A_DEVICE),a2
  578.     moveq    #NumSigs-1,d2    ;Number of signals to allocate-1
  579. .SigLoop:
  580.     moveq    #-1,d0    ;-1 is any signal at all
  581.     SYS    AllocSignal    ;Allocate signals for I/O interrupts
  582.     moveq    #0,d1    ;Convert bit number signal mask
  583.     bset    d0,d1
  584.     move.l    d1,(a2)+    ;Save in unit structure
  585.     dbra    d2,.SigLoop
  586.  
  587.     moveq    #-1,d0    ;-1 is any signal at all
  588.     SYS    AllocSignal    ;Allocate a signal
  589.     move.b    d0,TaskPort+MP_SIGBIT(A_DEVICE)
  590.     move.b    #PA_SIGNAL,TaskPort+MP_FLAGS(A_DEVICE)    ;Make message port "live"
  591.  
  592.     moveq    #-1,d0    ;-1 is any signal at all
  593.     SYS    AllocSignal    ;Allocate a signal
  594.     move.b    d0,TimerPort+MP_SIGBIT(A_DEVICE)
  595.     move.l    ThisTask(a6),TimerPort+MP_SIGTASK(A_DEVICE)
  596.  
  597.     moveq    #-1,d0    ;-1 is any signal at all
  598.     SYS    AllocSignal    ;Allocate a signal
  599.     move.b    d0,DiskResourcePort+MP_SIGBIT(A_DEVICE)
  600.     move.l    ThisTask(a6),DiskResourcePort+MP_SIGTASK(A_DEVICE)
  601.  
  602.     bsr    GetDrive
  603.     bsr    Inquire
  604.  
  605. ;Get drive types
  606.     moveq    #MD_NUMUNITS-1,d0
  607.     lea    Unit0(A_DEVICE),A_UNIT
  608. .TypeLoop:
  609.     bsr    GetDriveType
  610.     lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  611.     dbra    d0,.TypeLoop
  612.  
  613.     bsr    SeekZeroAll    ;Send all drives to track zero.
  614.     bsr    FreeDrive
  615.  
  616.     bra    .NextMessage
  617.  
  618. ;Main loop: Wait for a new message and handle disk changes.
  619.  
  620. .MainLoop:
  621.     moveq    #0,d0
  622.     move.b    MP_SIGBIT+TaskPort(A_DEVICE),d1
  623.     bset    d1,d0
  624.     move.l    #500000,d1
  625.     bsr    TimeOutWait
  626.     tst.l    d0
  627.     bne    .NextMessage
  628.  
  629. ;0.5 seconds have passed without receiving any work, so we check for disk
  630. ;changes, then drop into .NextMessage.
  631. ;Note: A6 undefined.
  632.  
  633. .CheckDiskChange:
  634.     moveq    #MD_NUMUNITS-1,d2
  635.     move.b    InquireBits(A_DEVICE),d3
  636.     lea    Unit0(A_DEVICE),A_UNIT
  637.     bsr    GetDrive
  638.     move.l    TimerIORequest+IO_DEVICE(A_DEVICE),a6
  639.  
  640. ;Algorithm (for each unit):
  641. ;Check hardware diskchange bit. If disk was ejected, seek to track zero,
  642. ;clear DiskInDrive bit. End.
  643. ;If no disk in drive, check NoClick bit. If set, immediately step toward
  644. ;track zero (using custom step routine). If clear, check the
  645. ;Drive_LastChecked time against the current time. If less than 2.5 seconds,
  646. ;End. If >2.5 seconds, step the head toward track zero, unless already on
  647. ;track zero. Check the hardware diskchange bit. If a disk is present in the
  648. ;drive set the DiskInDrive bit and check the hardware write protect status,
  649. ;setting WriteProtected as needed. End.
  650. ;Note: We also increment the diskchange counter in the public part of the
  651. ;unit structure, if a disk was inserted or removed.
  652.  
  653. .UnitLoop:
  654.     move.b    UnitNum(A_UNIT),d4
  655.     btst    d4,d3
  656.     beq    .NoCheck
  657.  
  658.     lea    TempTimeVal(A_DEVICE),a0
  659.     bsr    GetSysTime
  660.  
  661.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  662.     beq    .ThinkNoDisk
  663.     bsr    SelectDriveSameMotor
  664.     btst    #CIAB_DSKCHANGE,ciaapra
  665.     bne    .NoChange
  666. ;Disk was removed.
  667.     bclr    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  668.     bsr    SeekZero
  669.     bsr    MotorOff
  670.     bsr    Clear
  671.     bra    .Change
  672. .ThinkNoDisk:
  673.     btst    #TDPB_NOCLICK,TDU_PUBFLAGS(A_UNIT)
  674.     beq    .Click
  675.     bsr    SelectDriveSameMotor
  676.     bset    #CIAB_DSKDIREC,ciabprb    ;set to "out" (lower tracks)
  677.     bset    #CIAB_DSKSTEP,ciabprb
  678.     bclr    #CIAB_DSKSTEP,ciabprb    ;step head
  679.     bset    #CIAB_DSKSTEP,ciabprb
  680.     bsr    Deselect
  681.     move.l    TDU_SETTLEDELAY(A_UNIT),d0
  682.     bsr    delay
  683.     bsr    SelectDriveSameMotor
  684.     bra    .ChkChg
  685. .Click:
  686.     lea    Drive_LastCheck(A_UNIT),a1
  687.     SYS    SubTime
  688.     cmp.l    #2,TV_SECS(a0)
  689.     blo    .NoCheck
  690.     bhi    .SkipMicro
  691.     cmp.l    #500000,TV_MICRO(a0)
  692.     blo    .NoCheck
  693. .SkipMicro:
  694.     lea    Drive_LastCheck(A_UNIT),a0
  695.     bsr    GetSysTime
  696.     move.b    UnitNum(A_UNIT),d2    ;for Seek
  697.     move.w    TDU_CURRTRK(A_UNIT),d3
  698.     subq.w    #2,d3
  699.     bpl    .NotZero
  700.     moveq    #2,d3
  701. .NotZero:    bsr    SelectDriveSameMotor
  702.     bsr    SeekNoUpdate
  703. .ChkChg:    btst    #CIAB_DSKCHANGE,ciaapra
  704.     beq    .NoChange    ;no disk in drive
  705.     bset    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  706.     bclr    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  707.     btst    #CIAB_DSKPROT,ciaapra
  708.     bne    .Change    ;not write protected
  709.     bset    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  710. .Change:    bsr    GetDriveType    ;reread drive type (leaves drive deselected)
  711. ;    bsr    Deselect
  712.     addq.l    #1,TDU_COUNTER(A_UNIT)
  713.  
  714. ;This code notifies users of TD_REMOVE and TD_ADDCHANGEINT via Cause.
  715.  
  716.     push    a6
  717.     move.l    4,a6
  718.     SYS    Forbid
  719.     move.l    TDRemoveInt(A_UNIT),d0
  720.     beq    .NoRemoveInt
  721.     move.l    d0,a1
  722.     SYS    Cause
  723. .NoRemoveInt:
  724.     move.l    ChangeIntList+LH_HEAD(A_UNIT),a2
  725. .IntLoop:    move.l    (a2),d0
  726.     beq    .DoneInt
  727.     move.l    IO_DATA(a2),a1
  728.     move.l    d0,a2
  729.     SYS    Cause
  730.     bra    .IntLoop
  731. .DoneInt:    SYS    Permit
  732.     pop    a6
  733. .NoChange:
  734.     lea    LastCheck(A_DEVICE),a0
  735.     bsr    GetSysTime
  736. .NoCheck:
  737.     lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  738.     dbra    d2,.UnitLoop
  739.     move.l    4,a6
  740.     bsr    FreeDrive
  741.  
  742. .NextMessage:
  743.     btst    #DEVB_Stopped,DEV_FLAGS(A_DEVICE)    ;See if we are stopped
  744.     bne    .MainLoop    ;device is stopped, so ignore messages
  745.  
  746.     lea    TaskPort(A_DEVICE),a0
  747.     SYS    GetMsg    ;Get the next request
  748.     tst.l    d0
  749.     beq    .MainLoop    ;no message?
  750.     move.l    d0,A_IO    ;Do this request
  751.     move.l    IO_UNIT(A_IO),A_UNIT
  752.  
  753. ;Handle TDB_EXTCOM and dispatch command
  754.     move.w    IO_COMMAND(A_IO),d0
  755.  
  756.     IFNE    INFO_LEVEL
  757.     swap    d0
  758.     clr.w    d0
  759.     swap    d0
  760.     move.l    d0,-(sp)
  761.     PUTDEBUG    <'Command=%ld'>
  762.     addq.l    #4,sp
  763.     ENDC
  764.  
  765.     bclr    #TDB_EXTCOM,d0
  766.     beq    .NoExt
  767.     move.l    TDU_COUNTER(A_UNIT),d1
  768.     cmp.l    IOTD_COUNT(A_IO),d1
  769.     bls    .NoExt
  770. .ChgErr:    PUTDEBUG    <'Change error!'>
  771.     move.b    #TDERR_DiskChanged,IO_ERROR(A_IO)
  772.     bra    .Reply
  773. .NoExt:    move.l    #%000000111000111000011100,d1    ;specifies which commands should check for disk
  774.     btst    d0,d1
  775.     beq    .NoDiskNeeded
  776.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  777.     beq    .ChgErr
  778. .NoDiskNeeded:
  779.     bsr    GetDrive
  780.     lea    CmdTable(pc),a0
  781.     add.w    d0,d0
  782.     add.w    (a0,d0.w),a0
  783.     moveq    #0,d7    ;clear error flag
  784.     jsr    (a0)
  785.     bsr    FreeDrive
  786.     cmp.w    #TD_ADDCHANGEINT,IO_COMMAND(A_IO)
  787.     beq    .SkipReply
  788. .Reply:    move.l    A_IO,a1
  789.     SYS    ReplyMsg
  790. .SkipReply:
  791.  
  792. ;If at least 0.5 seconds has passed since last checking diskchange, do so
  793. ;now.
  794.     move.l    TimerIORequest+IO_DEVICE(A_DEVICE),a6
  795.     lea    TempTimeVal(A_DEVICE),a0
  796.     bsr    GetSysTime
  797.     lea    LastCheck(A_DEVICE),a1
  798.     SYS    SubTime
  799.     tst.l    TV_SECS(a0)
  800.     bne    .CheckDiskChange
  801.     cmp.l    #500000,TV_MICRO(a0)
  802.     bhs    .CheckDiskChange
  803.     lea    LastCheck(A_DEVICE),a0
  804.     bsr    GetSysTime
  805.     move.l    4,a6
  806.     bra    .NextMessage
  807.  
  808. GetSysTime:
  809.     cmp.w    #36,LIB_VERSION(a6)
  810.     bls    .OldKS
  811.     jmp    _LVOGetSysTime(a6)
  812. .OldKS:
  813. ;Compatibility routine for 1.2/1.3
  814.     movem.l    d0-d1/a0-a2/a6,-(sp)
  815.     move.l    a0,a2
  816.     lea    TimerIORequest(A_DEVICE),a1
  817.     move.l    4,a6
  818.     move.w    #TR_GETSYSTIME,IO_COMMAND(a1)
  819.     SYS    DoIO
  820.     lea    TimerIORequest(A_DEVICE),a1
  821.     move.l    IOTV_TIME+TV_SECS(a1),TV_SECS(a2)
  822.     move.l    IOTV_TIME+TV_MICRO(a1),TV_MICRO(a2)
  823.     movem.l    (sp)+,d0-d1/a0-a2/a6
  824.     rts
  825.  
  826. ;******************** External device routines ***********************
  827.  
  828. Open:
  829.  
  830. ;A6 - device ptr
  831. ;A1 - IORequest
  832. ;D0 - unit number
  833. ;D1 - flags (not used)
  834.  
  835. ;Important: On error, MUST put -1 in IO_DEVICE. This routine has no return
  836. ;value in d0 (return code is in IO_ERROR).
  837.  
  838.     PUTDEBUG    <'Open: Entered'>
  839.     moveq    #MD_NUMUNITS,d1
  840.     cmp.l    d1,d0
  841.     bhs    .Error
  842.     btst    d0,InquireBits(a6)
  843.     beq    .Error
  844.     lea    Unit0(a6),a0
  845.     mulu.w    #MyUnit_Sizeof,d0
  846.     add.l    d0,a0
  847.     move.l    a0,IO_UNIT(a1)
  848.     addq.w    #1,LIB_OPENCNT(a6)
  849.     clr.b    IO_ERROR(a1)    ;no error
  850.     move.b    #NT_REPLYMSG,LN_TYPE(a1)    ;Mark IORequest as "complete"
  851.     PUTDEBUG    <'Open: Done'>
  852.     rts
  853. .Error:
  854.     PUTDEBUG    <'Open: Failed'>
  855.  
  856. ;VirusX didn't like this.
  857. ;    move.b    #IOERR_OPENFAIL,IO_ERROR(a1)
  858.  
  859. ;NOTE: Trackdisk will return TDERR_BadDriveType if TDB_ALLOW_NON_3_5 flag set
  860. ;in "flags" and the drive is not present. (This is just trivia).
  861.  
  862.     move.b    #TDERR_BadUnitNum,IO_ERROR(a1)
  863.     moveq    #-1,d0
  864.     move.l    d0,IO_DEVICE(a1)
  865.     rts
  866.  
  867. _Close:
  868.  
  869. ;A6 - device ptr
  870. ;A1 - IORequest
  871.  
  872. ;Must return either 0 or, if the device wishes to be unloaded, the segment
  873. ;list.
  874.  
  875.     PUTDEBUG    <'Close: Called'>
  876.     moveq    #0,d0
  877.     rts
  878.  
  879. Expunge:
  880.  
  881. ;A6 - device ptr
  882.  
  883. ;Must return either 0 or SegList ptr in D0.
  884.  
  885.     moveq    #0,d0
  886.     rts
  887.  
  888. BeginIO:
  889. ;A1 - IORequest
  890. ;A6 - device ptr
  891.  
  892.     movem.l    d7/a3-a6,-(sp)
  893.     move.l    a1,A_IO
  894.     move.l    IO_UNIT(A_IO),A_UNIT
  895.     move.l    a6,A_DEVICE
  896.     move.l    4,a6
  897.  
  898.     clr.b    IO_ERROR(A_IO)
  899.     move.b    #NT_MESSAGE,LN_TYPE(A_IO)    ;So WaitIO() is guaranteed to work
  900.  
  901. ;Decide whether the command is immediate or queued
  902.     move.w    IO_COMMAND(A_IO),d1
  903.     bclr    #15,d1
  904.     cmp.w    #HighestCommand,d1
  905.     bhi    .BadCmd
  906.     move.l    #%111011001111000110000011,d0    ;specifies what commands are immediate
  907.     btst    d1,d0
  908.     beq    .Queue
  909.     add.w    d1,d1
  910.     lea    CmdTable(pc),a0
  911.     add.w    (a0,d1.w),a0
  912.     moveq    #0,d7    ;clear error flag
  913.     jsr    (a0)
  914. .Reply:    btst    #IOB_QUICK,IO_FLAGS(A_IO)
  915.     bne    .End
  916.     move.l    A_IO,a1
  917.     SYS    ReplyMsg
  918. .End:    movem.l    (sp)+,d7/a3-a6
  919.     rts
  920. .Queue:    bclr    #IOB_QUICK,IO_FLAGS(A_IO)    ;We did NOT complete this quickly
  921.     lea    TaskPort(A_DEVICE),a0
  922.     move.l    A_IO,a1
  923.     SYS    PutMsg
  924.     bra    .End
  925. .BadCmd:    move.b    #IOERR_NOCMD,IO_ERROR(a1)
  926.     bra    .Reply
  927.  
  928. AbortIO:
  929.  
  930. ;A6 - device ptr
  931. ;A1 - IORequest
  932.  
  933.     move.b    #IOERR_ABORTED,IO_ERROR(a1)    ;We always say we succeed(ed)
  934.     moveq    #0,d0    ;another success code
  935.     rts
  936.  
  937. ;**************** Device command (IO_COMMAND) routines *************************
  938.  
  939. ;Note: A6 = ExecBase upon entering a command routine.
  940. ;The low-level routines load $DFF000 into A6 when needed.
  941.  
  942. SaveRegs    setrl    d0-d3/d6-d7/a0-a2/a6
  943.  
  944. Read:
  945.     PUTDEBUG    <'Read: Called'>
  946.     movem.l    SaveRegs,-(sp)
  947.     bsr    RWSetup
  948.     tst.l    d7
  949.     bne    FinishRW
  950.  
  951.     bsr    DISK_Update    ;required because of complex write scheme
  952. ;Check for sector label nonsense
  953.     tst.b    IO_COMMAND(A_IO)
  954.     bpl    .NoLabel
  955.     move.l    IOTD_SECLABEL(A_IO),d2
  956.     bne    ReadSecLabel
  957. .NoLabel:
  958.  
  959.     bsr    DISK_Read
  960.     PUTDEBUG    <'Read: Done'>
  961.     bra    FinishRW
  962. Format:
  963. Write:    movem.l    SaveRegs,-(sp)
  964.     bsr    RWSetup
  965.     tst.l    d7
  966.     bne    FinishRW
  967.  
  968. ;Check for sector label nonsense
  969.     tst.b    IO_COMMAND(A_IO)
  970.     bpl    .NoLabel
  971.     move.l    IOTD_SECLABEL(A_IO),d2
  972.     bne    WriteSecLabel
  973. .NoLabel:
  974.  
  975.     bsr    DISK_Write
  976. FinishRW:    clr.l    IO_ACTUAL(A_IO)
  977.     move.b    d7,IO_ERROR(A_IO)
  978.     bne    .Skip
  979.     move.l    IO_LENGTH(A_IO),IO_ACTUAL(A_IO)
  980. .Skip:    movem.l    (sp)+,SaveRegs
  981.     rts
  982. RWSetup:
  983.     move.l    SectorsPerTrack(A_UNIT),d6
  984.     lsl.l    #8,d6
  985.     add.l    d6,d6    ;*512
  986.     move.l    #_custom,a6
  987.     move.l    IO_LENGTH(A_IO),d0
  988.     move.l    IO_OFFSET(A_IO),d1
  989.     move.l    IO_DATA(A_IO),a0
  990.     move.l    d1,d2    ;offset
  991.     add.l    d0,d2    ;length
  992.     cmp.l    BytesPerDisk(A_UNIT),d2
  993.     bhi    .Error
  994.     bsr    SelectDrive
  995.     bra    SelectSide
  996. .Error:    moveq    #DISK_BadParameter,d7
  997.     rts
  998.  
  999. ;Here are the routines for dealing with read/write requests that involve
  1000. ;the sector label. Note that, unlike the usual read/write routines of my
  1001. ;trackdisk, the normal parameter restrictions (e.g. IO_OFFSET and IO_LENGTH
  1002. ;must be a multiple of 512) MUST be observed. And I don't check for illegal
  1003. ;parameters, either. These routines are optimized for compactness rather
  1004. ;than performance because they are rarely (if ever) used.
  1005. ;Enter with:
  1006. ;IO_LENGTH: D0
  1007. ;IO_OFFSET: D1
  1008. ;IO_DATA:   A0
  1009.  
  1010. ReadSecLabel:
  1011.     PUTDEBUG    <'READSECLABEL!'>
  1012.  
  1013.     move.l    d2,a1
  1014.     move.l    d0,d2
  1015.     move.l    #512,d0
  1016. .Read:    bsr    DISK_Read
  1017.     move.l    d1,d3
  1018.     add.l    d0,d1
  1019.     add.l    d0,a0
  1020.     divu.w    d6,d3    ;offset/tracksize
  1021.     swap    d3    ;remainder=sector# (in bytes)
  1022.     lsr.w    #5,d3    ;divide by 32 to get label offset
  1023.     lea    SectorLabels(A_DEVICE),a2
  1024.     lea    (a2,d3.w),a2    ;get pointer to label
  1025.     moveq    #3,d3
  1026. ..    move.l    (a2)+,(a1)+    ;copy label
  1027.     dbra    d3,..
  1028.     sub.l    d0,d2
  1029.     bne    .Read
  1030.     bra    FinishRW
  1031.  
  1032. WriteSecLabel:
  1033.     PUTDEBUG    <'WRITESECLABEL!'>
  1034.  
  1035.     move.l    d2,a1
  1036.     move.l    d0,d2
  1037. .Write:
  1038.     move.l    d1,d3
  1039.     divu.w    d6,d3    ;offset/tracksize
  1040.     swap    d3    ;remainder=sector# (in bytes)
  1041.     lsr.w    #5,d3    ;divide by 32 to get label offset
  1042.  
  1043. ;We check to see whether we can write a full track. (Somehow, I can't
  1044. ;ignore performance completely :-)).
  1045.     tst.w    d3
  1046.     bne    .Read
  1047.     cmp.l    d6,d0
  1048.     bhs    .FullTrack
  1049. .Read:    moveq    #0,d0
  1050.     bsr    DISK_Read    ;force a track read
  1051.     lea    SectorLabels(A_DEVICE),a2
  1052.     lea    (a2,d3.w),a2    ;get pointer to label
  1053.     moveq    #3,d3
  1054. ..    move.l    (a1)+,(a2)+    ;copy label
  1055.     dbra    d3,..
  1056.     move.l    #512,d0
  1057. .L1:    bsr    DISK_Write
  1058.     add.l    d0,d1
  1059.     add.l    d0,a0
  1060.     sub.l    d0,d2
  1061.     bne    .Write
  1062.     bra    FinishRW
  1063. .FullTrack:
  1064.     lea    SectorLabels(A_DEVICE),a2
  1065.     moveq    #((16*22)/4)-1,d3
  1066. ..    move.l    (a1)+,(a2)+    ;copy all sector labels
  1067.     dbra    d3,..
  1068.     move.l    d6,d0
  1069.     bra    .L1
  1070.  
  1071. Update:    move.l    d7,-(sp)
  1072.     moveq    #0,d7
  1073.     bsr    DISK_Update
  1074.     move.b    d7,IO_ERROR(A_IO)
  1075.     move.l    (sp)+,d7
  1076.     rts
  1077.  
  1078. Clear:
  1079. ;This routine marks the track buffer as invalid.
  1080.     st    BufferDrive(A_DEVICE)
  1081.     bclr    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  1082.     rts
  1083.  
  1084. Motor:
  1085. ;Controls the drive motor
  1086. ;If IO_LENGTH=1, motor on
  1087. ;   IO_LENGTH=0, motor off
  1088. ;Old motor state (0=off, anything else means on) stored in IO_ACTUAL.
  1089.  
  1090.     push    d2
  1091.     clr.l    IO_ACTUAL(A_IO)
  1092.     move.b    UnitNum(A_UNIT),d2
  1093.     btst    d2,MotorState(A_DEVICE)
  1094.     beq    .WasOff
  1095.     move.l    #1,IO_ACTUAL(A_IO)
  1096. .WasOff:    tst.l    IO_LENGTH(A_IO)
  1097.     beq    .Off
  1098. ;Turn motor on
  1099.     bsr    SelectDrive
  1100.     bra    .End
  1101. .Off:
  1102. ;Turn motor off
  1103.     bclr    d2,MotorState(A_DEVICE)
  1104.     bsr    Deselect
  1105.     bset    #CIAB_DSKMOTOR,ciabprb    ;motor off
  1106.     addq.b    #3,d2
  1107.     bclr    d2,ciabprb    ;select drive X
  1108. .End:    pop    d2
  1109.     rts
  1110.  
  1111. ChangeState:
  1112. ;Returns whether there is a disk currently in the drive
  1113. ;IO_ACTUAL=0 if disk in drive
  1114. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1115.  
  1116.     clr.l    IO_ACTUAL(A_IO)
  1117.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  1118.     bne    .End
  1119.     move.l    #1,IO_ACTUAL(A_IO)    ;no disk in drive
  1120. .End:    rts
  1121.  
  1122. ChangeNum:
  1123. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1124.     move.l    TDU_COUNTER(A_UNIT),IO_ACTUAL(A_IO)
  1125.     rts
  1126.  
  1127. ProtStatus:
  1128. ;IO_ACTUAL=0 if disk is not write protected
  1129. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1130.  
  1131. ;Very important for compatibility: we must return an error (disk changed)
  1132. ;if there's no disk in the drive.
  1133.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  1134.     bne    .OK
  1135.     move.b    #TDERR_DiskChanged,IO_ERROR(A_IO)
  1136.     rts
  1137.  
  1138. .OK:    clr.l    IO_ACTUAL(A_IO)
  1139.     btst    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  1140.     beq    .End    ;not write protected
  1141.     move.l    #1,IO_ACTUAL(A_IO)    ;no disk in drive
  1142. .End:    rts
  1143.  
  1144. TDGetDriveType:
  1145. ;Returns type of drive in IO_ACTUAL
  1146. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1147.     clr.l    IO_ACTUAL(A_IO)
  1148.     move.b    DriveType(A_UNIT),IO_ACTUAL+3(A_IO)
  1149.     rts
  1150.  
  1151. GetNumTracks:
  1152. ;Returns number of tracks (note: not cylinders) in IO_ACTUAL
  1153. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1154.  
  1155.     clr.l    IO_ACTUAL(A_IO)
  1156.     move.b    NumTracks(A_UNIT),IO_ACTUAL+3(A_IO)
  1157.     rts
  1158.  
  1159. GetGeometry:
  1160. ;Fills in DriveGeometry structure pointed to by IO_DATA
  1161.     movem.l    d0-d1/a0,-(sp)
  1162.     move.l    IO_DATA(A_IO),a0
  1163.     move.l    #512,dg_SectorSize(a0)    ;in bytes
  1164.     move.l    #2,dg_Heads(a0)    ;number of surfaces
  1165.     clr.l    dg_BufMemType(a0)    ;preferred buffer memory type
  1166.     clr.b    dg_DeviceType(a0)    ;codes as defined in the SCSI-2 spec
  1167.     move.b    #DGF_REMOVABLE,dg_Flags(a0)    ;flags, including removable
  1168.     clr.w    dg_Reserved(a0)
  1169.     move.l    SectorsPerTrack(A_UNIT),d0
  1170.     move.l    d0,dg_TrackSectors(a0)    ;number of sectors/track
  1171.     add.l    d0,d0
  1172.     move.l    d0,dg_CylSectors(a0)    ;number of sectors/cylinder
  1173.     moveq    #0,d1
  1174.     move.b    NumTracks(A_UNIT),d1
  1175.     lsr.l    #1,d1    ;convert tracks -> cylinders
  1176.     move.l    d1,dg_Cylinders(a0)    ;number of cylinders
  1177.     mulu.w    d0,d1
  1178.     move.l    d1,dg_TotalSectors(a0)    ;total # of sectors on drive
  1179.     movem.l    (sp)+,d0-d1/a0
  1180.     rts
  1181.  
  1182. MyStop:    bset    #DEVB_Stopped,DEV_FLAGS(A_DEVICE)
  1183.     bsr    Update
  1184.     bra    Clear
  1185. Start:    movem.l    d0-d1/a0-a1,-(sp)
  1186.     bclr    #DEVB_Stopped,DEV_FLAGS(A_DEVICE)
  1187.     moveq    #0,d0
  1188.     move.b    MP_SIGBIT+TaskPort(A_DEVICE),d1
  1189.     bset    d1,d0
  1190.     lea    Task(A_DEVICE),a1
  1191.     SYS    Signal
  1192.     movem.l    (sp)+,d0-d1/a0-a1
  1193.     rts
  1194.  
  1195. ;Note: This seek routine can't really be depended on by user programs,
  1196. ;because the disk.resource will corrupt the side select bit.
  1197. TDSeek:    movem.l    d0/d3,-(sp)
  1198.     bsr    SelectDriveSameMotor
  1199.     move.l    IO_OFFSET(A_IO),d3
  1200.     cmp.l    BytesPerDisk(A_UNIT),d3
  1201.     bhs    .Error
  1202.     move.l    SectorsPerTrack(A_UNIT),d0
  1203.     lsl.l    #8,d0
  1204.     add.l    d0,d0    ;*512 = bytes per track
  1205.     divu.w    d0,d3
  1206.     bsr    Seek
  1207. .End:    movem.l    (sp)+,d0/d3
  1208.     rts
  1209. .Error:    move.b    #TDERR_NotSpecified,IO_ERROR(A_IO)
  1210.     bra    .End
  1211.  
  1212. TDRawRead:
  1213.     movem.l    d0-d1/d3/a6,-(sp)
  1214.     move.l    #_custom,a6
  1215.     moveq    #0,d1
  1216.     bsr    DoRaw
  1217.     movem.l    (sp)+,d0-d1/d3/a6
  1218.     rts
  1219.  
  1220. RawWrite:
  1221.     movem.l    d0-d1/d3/a6,-(sp)
  1222.     move.l    #_custom,a6
  1223.     btst    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  1224.     bne    .WPErr
  1225.     move.w    #1<<14,d1
  1226.     bsr    DoRaw
  1227.     move.l    #3*1000,d0
  1228.     bsr    delay    ;post-write delay
  1229. .End:    movem.l    (sp)+,d0-d1/d3/a6
  1230.     rts
  1231. .WPErr:    move.b    #TDERR_WriteProt,IO_ERROR(A_IO)
  1232.     bra    .End
  1233.  
  1234. DoRaw:
  1235. ;Enter with bit 14 set in d1 according to read/write (for dsklen)
  1236. ;Uses d0-d1/d3 (not saved)
  1237. ;Assumes $dff000 in A6
  1238.  
  1239.     clr.l    IO_ACTUAL(A_IO)
  1240.     bsr    SelectDrive
  1241.     move.l    IO_OFFSET(A_IO),d3
  1242.     cmp.b    NumTracks(A_UNIT),d3
  1243.     bhs    .Error
  1244.     bsr    Seek
  1245.     tst.l    d7
  1246.     bne    .Error
  1247.  
  1248.     move.l    IO_DATA(A_IO),dskpt(a6)
  1249.     move.w    #ADKF_WORDSYNC,adkcon(a6)
  1250.     btst    #IOTDB_WORDSYNC,IO_FLAGS(A_IO)
  1251.     beq    .SkipSync
  1252.     move.w    #ADKF_SETCLR+ADKF_WORDSYNC,adkcon(a6)
  1253. .SkipSync:
  1254.     move.w    #ADKF_MSBSYNC,adkcon(a6)
  1255.     move.w    #ADKF_SETCLR+ADKF_FAST+ADKF_MFMPREC,adkcon(a6)
  1256.     bsr    PreComp
  1257.     move.w    #DMAF_SETCLR+DMAF_MASTER+DMAF_DISK,dmacon(a6)    ;enable disk DMA
  1258.     move.w    #$4489,dsksync(a6)    ;set magic sync word
  1259.     bsr    ClearSigs
  1260.     move.w    #INTF_SETCLR+INTF_DSKBLK,intena(a6)    ;enable int
  1261.     move.l    IO_LENGTH(A_IO),d0
  1262.  
  1263.     cmp.l    #32766,d0
  1264.     bhi    .Error
  1265.     lsr.l    #1,d0
  1266.     bset    #15,d0
  1267.     or.w    d1,d0
  1268.  
  1269.     btst    #IOTDB_INDEXSYNC,IO_FLAGS(A_IO)
  1270.     beq    .NoIndex
  1271.     move.w    d0,IndexDskLen(A_DEVICE)
  1272.     bsr    EnableIndex
  1273.     bra    .Wait
  1274. .NoIndex:
  1275.  
  1276.     move.w    d0,dsklen(a6)
  1277.     move.w    d0,dsklen(a6)
  1278. .Wait:    move.l    BlockSig(A_DEVICE),d0
  1279.     move.l    #900*1000*2,d1
  1280.     bsr    TimeOutWait
  1281.     beq    .NoSync
  1282.     move.w    #0,dsklen(a6)
  1283.     move.w    #INTF_DSKBLK,intena(a6)    ;disable int
  1284. .EndIO:    bsr    DisableIndex
  1285.     bsr    ClearSigs
  1286.     tst.b    IO_ERROR(A_IO)
  1287.     bne    .EndRTS
  1288.     move.l    IO_LENGTH(A_IO),IO_ACTUAL(A_IO)
  1289. .EndRTS:    rts
  1290. .Error:    move.b    #TDERR_NotSpecified,IO_ERROR(A_IO)
  1291.     rts
  1292. .NoSync:    bsr    StopDMA
  1293.     move.b    #TDERR_NoSecHdr,IO_ERROR(A_IO)
  1294.     bra    .EndIO
  1295.  
  1296.  
  1297. AddChangeInt:
  1298. ;This command uses the linkage fields of the IORequest to add a ChangeInt
  1299. ;request to a list maintained in the unit structure. This must NOT be
  1300. ;ReplyMsg'ed to avoid destroying the linkage fields - a special compare in
  1301. ;the task code handles this.
  1302.     movem.l    d0-d1/a0-a1,-(sp)
  1303.     move.l    A_IO,a1
  1304.     lea    ChangeIntList(A_UNIT),a0
  1305.     SYS    AddHead    ;could use any list add routine
  1306.     movem.l    (sp)+,d0-d1/a0-a1
  1307.     rts
  1308.  
  1309. RemChangeInt:
  1310. ;This command unlinks the AddChangeInt request from the task's port.
  1311. ;This is (and must be) an immediate command.
  1312. ;Note that because this command occurs asyncronously to the task code, the
  1313. ;task code that scans the ChangeInt list must be protected with a Forbid.
  1314.  
  1315.     movem.l    d0-d1/a0-a1,-(sp)
  1316.     SYS    Forbid
  1317.     move.l    A_IO,a1
  1318.     SYS    Remove
  1319.     SYS    Permit
  1320.     movem.l    (sp)+,d0-d1/a0-a1
  1321.     rts
  1322.  
  1323. TDRemove:
  1324. ;This command is obsolete, but is unfortuntely used by the ROM filesystem.
  1325. ;It accepts an Interrupt structure (for Cause) in IO_DATA. Only one user per
  1326. ;unit is permitted.
  1327.  
  1328.     tst.l    TDRemoveInt(A_UNIT)
  1329.     beq    .Ok
  1330.     move.b    #TDERR_DriveInUse,IO_ERROR(A_IO)
  1331.     rts
  1332. .Ok:    move.l    IO_DATA(A_IO),TDRemoveInt(A_UNIT)
  1333.     rts
  1334.  
  1335. GetDrive:
  1336. ;Obtain the use of this unit via disk.resource.
  1337.     movem.l    d0-d1/a0-a2/a6,-(sp)
  1338.     lea    DiskResourceUnit(A_DEVICE),a2
  1339. .GetUnit:    move.l    DiskResourceBase(A_DEVICE),a6
  1340.     move.l    a2,a1
  1341.     jsr    DR_GETUNIT(a6)
  1342.     tst.l    d0
  1343.     bne    .End
  1344.     lea    DiskResourcePort(A_DEVICE),a0
  1345.     move.l    4,a6
  1346.     SYS    WaitPort
  1347.     bra    .GetUnit
  1348. .End:    movem.l    (sp)+,d0-d1/a0-a2/a6
  1349.     rts
  1350.  
  1351. FreeDrive:
  1352. ;Release this unit to other users of disk.resource.
  1353.  
  1354.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1355.     move.l    DiskResourceBase(A_DEVICE),a6
  1356.     jsr    DR_GIVEUNIT(a6)
  1357.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1358.     rts
  1359.  
  1360. ;***************************** Low-level disk code **************************
  1361.  
  1362. ;Standard register usage:
  1363. ;A6            - $dff000
  1364. ;A5 (A_DEVICE) - device ptr
  1365. ;A4 (A_UNIT)   - unit ptr
  1366. ;A3 (A_IO)     - pointer to IO request
  1367.  
  1368. ;For reading/writing:
  1369. ;D0.L - length (bytes)
  1370. ;D1.L - offset (bytes)
  1371. ;A0.L - buffer
  1372.  
  1373. ;NOTE: Error code returned in D7.L - 0 if ok, else error
  1374.  
  1375. ;General errors
  1376. DISK_BadParameter    equ    TDERR_NotSpecified
  1377.  
  1378. ;Read errors
  1379. DISK_NoSync    equ    TDERR_NoSecHdr
  1380. DISK_BadHeader    equ    TDERR_BadHdrSum
  1381. DISK_BadData    equ    TDERR_BadSecSum
  1382.  
  1383. ;Write errors
  1384. DISK_WriteProtected    equ    TDERR_WriteProt
  1385. DISK_VerifyError    equ    TDERR_NotSpecified
  1386.  
  1387.     IFND    dskpt
  1388. dskpt    equ    dskpth
  1389.     ENDC
  1390.  
  1391. ;Note: This is a public value, but it is NOT meant to be changed!!!
  1392. DISK_RawBufSize    equ    13630
  1393.  
  1394. ciabprb    equ    $bfd100
  1395. ciaapra    equ    $bfe001
  1396. ciabddrb    equ    $bfd300
  1397. ciaaddra    equ    $bfe201
  1398.  
  1399. ***************************************************************
  1400. ;Important disk parameters, summary:
  1401.  
  1402. ;Step rate: 3ms. 4ms when looking for track zero.
  1403. ;Settle time: 15ms
  1404. ;Post-write delay: 3ms (officially 1.3ms)
  1405. ;Side select delay: 2ms (officially 1.3ms)
  1406. ***************************************************************
  1407.  
  1408. DISK_Read:
  1409.     movem.l    d0-d5/a0/a1,-(sp)
  1410.  
  1411.     move.l    a0,a1    ;destination ptr in A1
  1412.     move.l    d0,d5
  1413. .ReadLoop:
  1414.     move.l    d1,d3
  1415.     divu.w    d6,d3    ;d3.w is track #
  1416.     move.l    d3,d4
  1417.     clr.w    d4
  1418.     swap    d4    ;d4.l is byte offset into track
  1419.     bsr    MinSeek
  1420.     tst.l    d4    ;any offset?
  1421.     bne    .Complex    ;yes
  1422.     cmp.l    d6,d5    ;check remaining length
  1423.     blo    .Complex    ;if not a track, forget it
  1424.     move.l    a1,d0
  1425.     btst    #0,d0    ;word aligned?
  1426.     bne    .Complex    ;no, do it the long way
  1427.     move.l    a1,a0
  1428.     bsr    ReadTrackAndDecodeNoBuffer
  1429.     tst.l    d7
  1430.     bne    .End
  1431.     sub.l    d6,d5    ;update length
  1432.     beq    .End
  1433.     add.l    d6,a1    ;update destination pointer
  1434.     add.l    d6,d1    ;update offset
  1435.     bra    .ReadLoop
  1436.  
  1437. .Complex:
  1438.     move.l    DecodedBuffer(A_DEVICE),a0
  1439.     bsr    ReadTrackAndDecodeBuffered
  1440.     tst.l    d7
  1441.     bne    .End
  1442.     add.l    d4,a0
  1443.     sub.l    d6,d4
  1444.     neg.l    d4
  1445.     add.l    d4,d1    ;update offset
  1446.  
  1447. ;D4.L - number of bytes that could be transferred from this track
  1448. ;D5.L - number of bytes left in the entire Read request
  1449.  
  1450.     cmp.l    d5,d4
  1451.     bhs    .FinishUp
  1452.     sub.l    d4,d5    ;update length
  1453.     move.l    d4,d0
  1454.     bsr    CopyMem
  1455.     add.l    d0,a1    ;update destination pointer
  1456.     bra    .ReadLoop
  1457. .FinishUp:
  1458.     move.l    d5,d0
  1459.     bsr    CopyMem    ;use number of bytes left in entire request
  1460. .End:    movem.l    (sp)+,d0-d5/a0/a1
  1461.     rts
  1462.  
  1463. SelectDrive:
  1464. ;Selects drive AND turns on motor
  1465. ;Selects UnitNum(A_UNIT).
  1466.  
  1467.     movem.l    d0/d2,-(sp)
  1468.     move.b    UnitNum(A_UNIT),d2
  1469.     bsr    Deselect
  1470.     bclr    #CIAB_DSKMOTOR,ciabprb    ;motor on
  1471.     move.l    d2,d0
  1472.     addq.b    #3,d0
  1473.     bclr    d0,ciabprb    ;select drive X
  1474.     bset    d2,MotorState(A_DEVICE)
  1475.  
  1476.     moveq    #4,d2
  1477. .Wait:    btst    #CIAB_DSKRDY,ciaapra
  1478.     beq    .End
  1479.     move.l    #100*1000,d0
  1480.     bsr    delay
  1481.     dbra    d2,.Wait    
  1482.  
  1483. .End:    movem.l    (sp)+,d0/d2
  1484.     rts
  1485.  
  1486. Deselect:    or.b    #CIAF_DSKSEL0+CIAF_DSKSEL1+CIAF_DSKSEL2+CIAF_DSKSEL3,ciabprb    ;Deselect all drives
  1487.     rts
  1488.  
  1489. SelectDriveSameMotor:
  1490. ;Select a drive WITHOUT changing the current motor state
  1491. ;Selects UnitNum(A_UNIT).
  1492.  
  1493.     push    d2
  1494.     move.b    UnitNum(A_UNIT),d2
  1495.     bsr    Deselect
  1496.     bclr    #CIAB_DSKMOTOR,ciabprb    ;motor on
  1497.     btst    d2,MotorState(A_DEVICE)
  1498.     bne    .WasOn
  1499.     bset    #CIAB_DSKMOTOR,ciabprb    ;motor off
  1500. .WasOn:    addq.b    #3,d2
  1501.     bclr    d2,ciabprb    ;select drive X
  1502.     pop    d2
  1503. _RTS:    rts
  1504.  
  1505. DISK_Update:
  1506. ;Flush track buffer if "dirty"
  1507.  
  1508.     bclr    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  1509.     beq    _RTS
  1510.     movem.l    d0-d2/a0/a2/a6,-(sp)
  1511.     move.l    #_custom,a6
  1512.  
  1513. ;This is somewhat tricky, because the currently selected drive may not be
  1514. ;the drive that we want to write to!
  1515.     move.b    UnitNum(A_UNIT),d0
  1516.     move.w    TDU_CURRTRK(A_UNIT),d1
  1517.     move.b    BufferDrive(A_DEVICE),UnitNum(A_UNIT)    ;fake drive
  1518.     move.b    BufferTrack(A_DEVICE),TDU_CURRTRK+1(A_UNIT)    ;fake track
  1519.     bsr    SelectDrive
  1520.     bsr    SelectSide
  1521.  
  1522. ;The logic of this routine is complicated by the need to support the write
  1523. ;optimization scheme (see DISK_Write for details). What we need to do is
  1524. ;check the WriteMap to determine whether a ReadTrackAndDecode is required
  1525. ;before finally writing...
  1526.     move.l    WriteMap(A_DEVICE),d2
  1527.     and.l    SectorMask(A_UNIT),d2
  1528.     cmp.l    SectorMask(A_UNIT),d2
  1529.     beq    .SkipRead
  1530.     move.l    DecodedBuffer(A_DEVICE),a0
  1531.     bsr    ReadTrackAndDecode
  1532.     tst.l    d7
  1533.     bne    .End
  1534. .SkipRead:
  1535.     move.l    d7,WriteMap(A_DEVICE)
  1536.  
  1537.     move.l    DecodedBuffer(A_DEVICE),a2
  1538.     bsr    EncodeAndWriteTrack
  1539.     move.b    d0,UnitNum(A_UNIT)
  1540.     move.w    d1,TDU_CURRTRK(A_UNIT)
  1541.     bsr    SelectDrive
  1542. .End:    movem.l    (sp)+,d0-d2/a0/a2/a6
  1543.     rts
  1544.  
  1545. SelectSide:
  1546. ;Select the correct side based on current track. This routine MUST be
  1547. ;called by certain routines (e.g. Update, Write) because the side select is
  1548. ;lost after a GiveUnit!
  1549.     bclr    #CIAB_DSKSIDE,ciabprb    ;set to upper
  1550.     btst    #0,TDU_CURRTRK+1(A_UNIT)
  1551.     bne    .skip
  1552.     bset    #CIAB_DSKSIDE,ciabprb    ;set to lower
  1553. .skip:    push    d0
  1554.     move.l    #2*1000,d0
  1555.     bsr    delay
  1556.     pop    d0
  1557.     rts
  1558.  
  1559. ;Enter with destination track in d3.b
  1560.  
  1561. ;Note: This routine checks for valid track numbers -- if either the
  1562. ;current track number or the destination is invalid, PANIC.
  1563.  
  1564. SaveRegs    setrl    d0/d3-d4
  1565.  
  1566. SeekNoUpdate:
  1567. ;Perform a seek but don't call DISK_Update -- used by main routine when
  1568. ;checking for disk changes.
  1569.  
  1570.     movem.l    SaveRegs,-(sp)
  1571.     bra    SeekAfterUpdate
  1572.  
  1573. MinSeek:
  1574. ;Only call MinSeek if it is certain that the side select has not been
  1575. ;changed!
  1576.     cmp.b    TDU_CURRTRK+1(A_UNIT),d3
  1577.     bne    Seek
  1578.     move.w    d0,-(sp)
  1579.     move.b    BufferDrive(A_DEVICE),d0
  1580.     cmp.b    UnitNum(A_UNIT),d0
  1581.     bne    .Seek
  1582.     move.w    (sp)+,d0
  1583.     rts
  1584. .Seek:    move.w    (sp)+,d0
  1585.  
  1586. Seek:    movem.l    SaveRegs,-(sp)
  1587.  
  1588.     bsr    DISK_Update
  1589. SeekAfterUpdate:
  1590.     tst.l    d7
  1591.     bne    .End
  1592.  
  1593.     move.l    TDU_STEPDELAY(A_UNIT),d0
  1594.     cmp.b    NumTracks(A_UNIT),d3
  1595.     bhs    .Error
  1596.  
  1597. ;Set head
  1598.     bclr    #CIAB_DSKSIDE,ciabprb    ;set to upper
  1599.     btst    #0,d3
  1600.     bne    .skip
  1601.     bset    #CIAB_DSKSIDE,ciabprb    ;set to lower
  1602. .skip:
  1603.     move.w    TDU_CURRTRK(A_UNIT),d4
  1604.     lsr.b    #1,d4
  1605.     cmp.b    #80,d4
  1606.     bhs    .Error
  1607.     move.b    d3,TDU_CURRTRK+1(A_UNIT)
  1608.     lsr.b    #1,d3
  1609.     bset    #CIAB_DSKDIREC,ciabprb    ;set to "out" (lower tracks)
  1610.     sub.b    d3,d4
  1611.     beq    .SideSelectOnly
  1612.     bhi    .StepIn    ;Go if DISK_CurrentTrack > Destination
  1613.     bclr    #CIAB_DSKDIREC,ciabprb    ;set to "in" (higher tracks)
  1614.     neg.b    d4
  1615. .StepIn:
  1616.     bsr    SelectDriveSameMotor
  1617.     bset    #CIAB_DSKSTEP,ciabprb
  1618.     bclr    #CIAB_DSKSTEP,ciabprb    ;step head
  1619.     bset    #CIAB_DSKSTEP,ciabprb
  1620.     bsr    Deselect
  1621.     bsr    delay
  1622.     subq.b    #1,d4
  1623.     bne    .StepIn
  1624.     move.l    TDU_SETTLEDELAY(A_UNIT),d0
  1625.     bsr    delay
  1626.     bsr    SelectDriveSameMotor
  1627. .End:    movem.l    (sp)+,SaveRegs
  1628.     rts
  1629. .SideSelectOnly:
  1630.     move.l    #2*1000,d0
  1631.     bsr    delay
  1632.     bra    .End
  1633. .Error:
  1634. ;    move.w    #$f00,$dff180
  1635.     bra    .End
  1636.  
  1637. ;*************************** Delay code ****************************
  1638.  
  1639. delay:
  1640.  
  1641. ;Enter with microseconds in D0.L
  1642.  
  1643.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1644.     lea    TimerIORequest(A_DEVICE),a1
  1645.     move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
  1646.     clr.l    TV_SECS+IO_SIZE(a1)
  1647.     move.l    d0,TV_MICRO+IO_SIZE(a1)
  1648.     move.l    4,a6
  1649.     SYS    DoIO
  1650.  
  1651. ;Clear signal bit (TimeOutWait depends on the signal bit being 'correct').
  1652.     lea    TimerIORequest(A_DEVICE),a1
  1653.     move.l    MN_REPLYPORT(a1),a0
  1654.     move.b    MP_SIGBIT(a0),d0
  1655.     moveq    #0,d1
  1656.     bset    d0,d1
  1657.     moveq    #0,d0
  1658.     SYS    SetSignal
  1659.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1660.     rts
  1661.  
  1662. TimeOutWait:
  1663.  
  1664. ;Wait for signal mask in D0, but include a time-out specified in D1 (usecs).
  1665. ;Returns wait mask in D0, or 0 if a time-out occured (Z flag will be set).
  1666.  
  1667.     movem.l    d1-d4/a0-a2/a6,-(sp)
  1668.     move.l    d0,d3
  1669.     move.l    4,a6
  1670.     lea    TimerIORequest(A_DEVICE),a1
  1671.     move.l    a1,a2
  1672.     move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
  1673.     clr.l    TV_SECS+IO_SIZE(a1)
  1674.     move.l    d1,TV_MICRO+IO_SIZE(a1)
  1675.     move.l    MN_REPLYPORT(a1),a0
  1676.     moveq    #0,d2
  1677.     move.b    MP_SIGBIT(a0),d1
  1678.     bset    d1,d2
  1679.     SYS    SendIO
  1680.     move.l    d3,d0
  1681.     add.l    d2,d0    ;equivilent to OR in this case
  1682.     SYS    Wait
  1683.     and.l    d3,d0    ;exclude timer signal
  1684.     move.l    d0,d4
  1685.     beq    .TimeOut    ;if zero, timer signal was the only signal
  1686.     move.l    a2,a1
  1687.     SYS    AbortIO
  1688. .TimeOut:    move.l    a2,a1
  1689.     SYS    WaitIO
  1690.     moveq    #0,d0    ;value
  1691.     move.l    d2,d1    ;mask (timer sig)
  1692.     SYS    SetSignal    ;make SURE the timer signal is clear
  1693.     move.l    d4,d0
  1694.     movem.l    (sp)+,d1-d4/a0-a2/a6
  1695.     rts
  1696.  
  1697. ;*************************** Interrupt routines ************************
  1698.  
  1699. ;------------------------------------------
  1700. ;Register contents upon entering a handler:
  1701. ;D1 - (INTENAR) AND (INTREQR)
  1702. ;A0 - $dff000
  1703. ;A1 - data ptr (device ptr in this case)
  1704. ;A6 - ExecBase 
  1705.  
  1706. ;d0, d1, a0, a1, a5, and a6 are scratch.
  1707. ;-----------------------------------------
  1708.  
  1709. ;However, the disk.resource autodoc indicates the following arrangement for
  1710. ;interrupts installed by GetUnit:
  1711.  
  1712. ;D0/D1/A0/A1 are scratch
  1713. ;A1 points to IS_DATA (device pointer in this case).
  1714. ;Make no other assumptions!
  1715.  
  1716. SyncInt:    addq.w    #1,SyncCount(a1)
  1717.     move.l    SyncSig(a1),d0
  1718.     lea    Task(a1),a1
  1719.     push    a6
  1720.     move.l    4,a6
  1721.     SYS    Signal
  1722.     pop    a6
  1723.  
  1724. ;Delay approximately 63us to avoid two sync interrupts
  1725. ;This could be improved.
  1726.     moveq    #1,d0
  1727. .L1:    move.b    vhposr+_custom,d1
  1728. .L2:    cmp.b    vhposr+_custom,d1
  1729.     beq    .L2
  1730.     dbra    d0,.L1
  1731.     move.w    #INTF_DSKSYNC,intreq+_custom    ;clear sync
  1732.     rts    
  1733.  
  1734. BlockInt:
  1735.     push    a6
  1736.     move.l    #_custom,a6
  1737.     move.w    #INTF_DSKBLK,intreq(a6)
  1738.  
  1739. ;Test DEVB_Verify flag. If set, initiate a read into the verify buffer.
  1740.     bclr    #DEVB_Verify,DEV_FLAGS(a1)
  1741.     beq    .NoVerify
  1742.  
  1743.     move.w    #INTF_SETCLR+INTF_DSKSYNC,intena(a6)    ;enable sync int
  1744.     move.l    VerifyBuffer(a1),dskpt(a6)
  1745.     move.w    #ADKF_SETCLR+ADKF_WORDSYNC,adkcon(a6)
  1746.     move.w    #0,dsklen(a6)
  1747.     move.w    BlockIntDskLen(a1),dsklen(a6)
  1748.     move.w    BlockIntDskLen(a1),dsklen(a6)
  1749.     move.w    #$4489,dsksync(a6)    ;set magic sync word
  1750. ;Now the first sync interrupt we get will be known to be valid, because the
  1751. ;DMA read is fully started.
  1752.     bra    .End
  1753.  
  1754. .NoVerify:
  1755.     move.l    BlockSig(a1),d0
  1756.     lea    Task(a1),a1
  1757.     move.l    4,a6
  1758.     SYS    Signal
  1759. .End:    pop    a6
  1760.     rts
  1761.  
  1762. IndexInt:
  1763.     move.w    IndexDskLen(a1),d0
  1764.     beq    .End
  1765.     move.w    d0,dsklen+_custom
  1766.     move.w    d0,dsklen+_custom
  1767.     clr.w    IndexDskLen(a1)
  1768. .End:    rts
  1769.  
  1770. EnableIndex:
  1771.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1772.     move.l    CIABase(A_DEVICE),a6
  1773.     moveq    #16,d0
  1774.     SYS    SetICR    ;clear interrupt
  1775.     move.l    #16+128,d0
  1776.     SYS    AbleICR    ;enable interrupt
  1777.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1778.     rts
  1779. DisableIndex:
  1780.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1781.     move.l    CIABase(A_DEVICE),a6
  1782.     moveq    #16,d0
  1783.     SYS    AbleICR    ;disable interrupt
  1784.     moveq    #16,d0
  1785.     SYS    SetICR    ;clear interrupt
  1786.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1787.     rts
  1788.  
  1789. ;*********************** End interrupt routines ************************
  1790.  
  1791. ClearSigs:
  1792.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1793.     move.w    #INTF_DSKBLK+INTF_DSKSYNC,intreq+_custom    ;clear sync+done
  1794.     clr.w    SyncCount(A_DEVICE)
  1795.     clr.w    IndexDskLen(A_DEVICE)
  1796.     move.l    4,a6
  1797.     moveq    #0,d0    ;value
  1798.     move.l    SyncSig(A_DEVICE),d1
  1799.     add.l    BlockSig(A_DEVICE),d1
  1800.     SYS    SetSignal
  1801.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1802.     rts
  1803.  
  1804. SetRegs:
  1805. ;This routine enables the block interrupt, but leaves sync interrupts
  1806. ;disabled.
  1807.  
  1808.     move.l    RawBuffer(A_DEVICE),dskpt(a6)
  1809.     move.w    #ADKF_MSBSYNC+ADKF_PRECOMP0+ADKF_PRECOMP1,adkcon(a6)
  1810.     move.w    #ADKF_SETCLR+ADKF_FAST+ADKF_WORDSYNC+ADKF_MFMPREC,adkcon(a6)
  1811.     move.w    #DMAF_SETCLR+DMAF_MASTER+DMAF_DISK,dmacon(a6)    ;enable disk DMA
  1812.     bsr    ClearSigs
  1813.     move.w    #INTF_SETCLR+INTF_DSKBLK,intena(a6)    ;enable block int
  1814.     rts
  1815.  
  1816. PreComp:
  1817. ;Enter with $dff000 in A6
  1818.     movem.l    d0-d1,-(sp)
  1819.     move.w    #ADKF_PRECOMP0+ADKF_PRECOMP1,adkcon(a6)    ;no precomp
  1820.     move.w    TDU_CURRTRK(A_UNIT),d0
  1821.     cmp.w    TDU_COMP01TRACK(A_UNIT),d0
  1822.     bls    .End
  1823.     move.w    #ADKF_SETCLR+ADKF_PRECOMP0,d1
  1824.     cmp.w    TDU_COMP10TRACK(A_UNIT),d0
  1825.     bls    .Done
  1826.     move.w    #ADKF_SETCLR+ADKF_PRECOMP1,d1
  1827.     cmp.w    TDU_COMP11TRACK(A_UNIT),d0
  1828.     bls    .Done
  1829.     move.w    #ADKF_SETCLR+ADKF_PRECOMP0+ADKF_PRECOMP1,d1
  1830. .Done:    move.w    d1,adkcon(a6)
  1831. .End:    movem.l    (sp)+,d0-d1
  1832.     rts
  1833.  
  1834. ScanSync:
  1835. ;Scan for sync mark
  1836. ;A2 - pointer to raw data -- updated
  1837. ;Error code in D7
  1838.  
  1839.     bsr    WaitWordSync
  1840.     tst.l    d7
  1841.     bne    .End
  1842.  
  1843. ;This routine is trickier than it appears. The trick is that we must NOT
  1844. ;assume a $4489 at the beginning of our buffer. This phenomenon occurs when
  1845. ;the DMA starts in the middle of the first sync word. The second sync word
  1846. ;is thrown away by the hardware. It sounds exotic, but it actually happens
  1847. ;quite often!
  1848.  
  1849.     push    a0
  1850.     move.l    RawBuffer(A_DEVICE),a0
  1851.     cmp.l    a0,a2
  1852.     add.l    RawBufSize(A_UNIT),a0
  1853.     beq    .found    ;if start of buffer, don't scan for sync!!!
  1854.  
  1855. .Sync:    cmpi.w    #$4489,(a2)+
  1856.     beq    .found
  1857.     cmp.l    a2,a0
  1858.     bhi    .Sync
  1859. .Error:    pop    a0
  1860.     moveq    #DISK_NoSync,d7
  1861.     rts
  1862. .found:    cmpi.w    #$4489,(a2)
  1863.     bne    .ok
  1864.     addq.l    #2,a2
  1865.     cmp.l    a2,a0
  1866.     bhi    .found
  1867.     bra    .Error
  1868. .ok:    pop    a0
  1869. .End:    rts
  1870.  
  1871. StopDMA:    move.w    #0,dsklen(a6)
  1872.     move.w    #1<<15,dsklen(a6)
  1873.     move.w    #1<<15,dsklen(a6)    ;zero-length DMA transfer
  1874.     move.w    #INTF_DSKBLK+INTF_DSKSYNC,intena(a6)    ;disable ints
  1875.     bra    ClearSigs
  1876.  
  1877. WaitWordSync:
  1878. ;Wait for a sync mark or disk block done
  1879. ;Will return an error in 300ms if nothing happens.
  1880.  
  1881.     movem.l    d0-d1,-(sp)
  1882. .Wait:    tst.w    SyncCount(A_DEVICE)
  1883.     bne    .Sync
  1884.     move.l    SyncSig(A_DEVICE),d0
  1885.     add.l    BlockSig(A_DEVICE),d0
  1886.     move.l    #300*1000*2,d1    ;time-out (300ms)
  1887.     bsr    TimeOutWait
  1888.     beq    .Error
  1889.     and.l    BlockSig(A_DEVICE),d0
  1890.     bne    .Done
  1891.     bra    .Wait
  1892. .Sync:    subq.w    #1,SyncCount(A_DEVICE)
  1893. .End:    movem.l    (sp)+,d0-d1
  1894.     rts
  1895. .Done:    move.w    #$C000,SyncCount(A_DEVICE)    ;this is obscure - should change
  1896.     bra    .End
  1897. .Error:    moveq    #DISK_NoSync,d7
  1898.     bra    .End
  1899.  
  1900. ReadTrackAndDecodeBuffered:
  1901.     push    d0
  1902.     move.l    WriteMap(A_DEVICE),d0
  1903.     beq    .OK    ;no optimized writes to worry about
  1904.     and.l    SectorMask(A_UNIT),d0
  1905.     cmp.l    SectorMask(A_UNIT),d0
  1906.     beq    .End
  1907.     moveq    #-1,d0
  1908.     move.l    d0,WriteMap(A_DEVICE)    ;mark sectors as filled
  1909.     bra    .ReadTrack
  1910.  
  1911. .OK:    move.b    UnitNum(A_UNIT),d0
  1912.     cmp.b    BufferDrive(A_DEVICE),d0
  1913.     bne    .ReadTrack
  1914.     move.w    TDU_CURRTRK(A_UNIT),d0
  1915.     cmp.b    BufferTrack(A_DEVICE),d0
  1916.     bne    .ReadTrack
  1917. .End:    pop    d0
  1918.     rts
  1919. .ReadTrack:
  1920.     pop    d0
  1921.  
  1922. ReadTrackAndDecode:
  1923.  
  1924. ;Input: Buffer ptr in A0
  1925. ;Returns error code in D7
  1926.  
  1927.     move.b    UnitNum(A_UNIT),BufferDrive(A_DEVICE)
  1928.     move.b    TDU_CURRTRK+1(A_UNIT),BufferTrack(A_DEVICE)
  1929.  
  1930. ReadTrackAndDecodeNoBuffer:
  1931.     move.w    d0,-(sp)
  1932.     move.b    TDU_RETRYCNT(A_UNIT),d0
  1933. .Retry:    moveq    #0,d7
  1934.     bsr    ReadTrackAndDecodeNoRetry
  1935.     tst.l    d7
  1936.     beq    .End
  1937.     subq.b    #1,d0
  1938.     bpl    .Retry
  1939. ;Could not recover from error - clear the buffer
  1940.     bsr    Clear
  1941.  
  1942. .End:    move.w    (sp)+,d0
  1943.     rts
  1944.  
  1945. ReadTrackAndDecodeNoRetry:
  1946.     movem.l    d0-d6/a0-a2,-(sp)
  1947.  
  1948. ;Initiate a raw track read
  1949. ;Because we are using WORDSYNC interrupts, this code is VERY VERY tricky!!!!!
  1950.  
  1951.     bsr    SetRegs
  1952.     move.w    #$0123,dsksync(a6)    ;set invalid sync word
  1953. ;At this point sync interrupts will stop happenning, because $0123 will
  1954. ;(hopefully!) never occur. So, we clear the interrupt and enable it.
  1955.     bsr    ClearSigs
  1956.     move.w    #INTF_SETCLR+INTF_DSKSYNC,intena(a6)    ;enable sync int
  1957.     move.w    #0,dsklen(a6)
  1958.     move.w    ReadDskLen(A_UNIT),dsklen(a6)
  1959.     move.w    ReadDskLen(A_UNIT),dsklen(a6)
  1960.     move.w    #$4489,dsksync(a6)    ;set magic sync word
  1961.  
  1962. ;Now the first sync interrupt we get will be known to be valid, because the
  1963. ;DMA read is fully started.
  1964.  
  1965. ;Decode track
  1966.     move.l    RawBuffer(A_DEVICE),a2
  1967.  
  1968.     move.l    SectorsPerTrack(A_UNIT),d3
  1969.     subq.l    #1,d3
  1970.     move.l    #$55555555,d2
  1971.  
  1972. ;Wait for first sync marks...
  1973.     bsr    WaitWordSync
  1974.     tst.l    d7
  1975.     bne    .End
  1976.  
  1977. .SecLoop:
  1978.     bsr    ScanSync
  1979.     tst.l    d7
  1980.     bne    .End
  1981.  
  1982.     bsr    DecodeLong    ;get header
  1983.     subq.l    #8,a2
  1984.  
  1985.     and.w    #$ff00,d0    ;mask off sector number
  1986.     move.l    d0,d1
  1987.     cmp.w    MaxValidSec(A_UNIT),d1
  1988.     bhi    .HeaderError
  1989.     add.w    d1,d1    ;convert to sector offset
  1990.     lsr.w    #4,d0    ;get sector label offset
  1991.     lea    SectorLabels(A_DEVICE),a1
  1992.     lea    (a1,d0.w),a1
  1993.  
  1994. ;This code supports the write optimization...
  1995.     lsr.w    #4,d0    ;sector number
  1996.     move.l    WriteMap(A_DEVICE),d4
  1997.     btst    d0,d4    ;should we avoid reading this sector?
  1998.     bne    .EndLoop    ;yes, skip to next sector
  1999.  
  2000.     move.l    d1,-(sp)
  2001.     moveq    #0,d5
  2002.     move.l    (a2)+,d0
  2003.     eor.l    d0,d5
  2004.     move.l    (a2)+,d0
  2005.     eor.l    d0,d5
  2006. ;Decode and checksum sector label
  2007.     moveq    #3,d6
  2008. .Label:    move.l    16(a2),d4
  2009.     eor.l    d4,d5
  2010.     and.l    d2,d4
  2011.     move.l    (a2)+,d1
  2012.     eor.l    d1,d5
  2013.     and.l    d2,d1
  2014.     add.l    d1,d1
  2015.     or.l    d1,d4
  2016.     move.l    d4,(a1)+
  2017.     dbra    d6,.Label
  2018.     and.l    d2,d5
  2019.     lea    16(a2),a2    ;point at header checksum
  2020.     move.l    (sp)+,d1
  2021.     bsr    DecodeLong    ;header checksum
  2022.     cmp.l    d0,d5
  2023.     bne    .HeaderError
  2024.  
  2025. ;Verify track position
  2026.     swap    d1
  2027.     cmp.b    TDU_CURRTRK+1(A_UNIT),d1
  2028.     bne    .WrongTrack
  2029.     swap    d1
  2030.  
  2031.     bsr    DecodeLong    ;data area checksum
  2032.     lea    (a0,d1.w),a1    ;compute destination
  2033.  
  2034. ;Decode and checksum data block
  2035.     moveq    #127,d6
  2036.     moveq    #0,d5
  2037. .L1:    move.l    512(a2),d4
  2038.     eor.l    d4,d5
  2039.     and.l    d2,d4
  2040.     move.l    (a2)+,d1
  2041.     eor.l    d1,d5
  2042.     and.l    d2,d1
  2043.     add.l    d1,d1
  2044.     or.l    d1,d4
  2045.     move.l    d4,(a1)+
  2046.     dbra    d6,.L1
  2047.     and.l    d2,d5
  2048.     lea    512(a2),a2
  2049.  
  2050.     cmp.l    d0,d5    ;check data area checksum
  2051.     bne    .DataError
  2052. .EndLoop:    dbra    d3,.SecLoop
  2053.  
  2054. .End:    bsr    StopDMA
  2055.     movem.l    (sp)+,d0-d6/a0-a2
  2056.     rts
  2057. .HeaderError:
  2058.     moveq    #DISK_BadHeader,d7
  2059.     bra    .End
  2060. .DataError:
  2061.     moveq    #DISK_BadData,d7
  2062.     bra    .End
  2063. .WrongTrack:
  2064.     moveq    #TDERR_SeekError,d7
  2065.     move.w    TDU_CURRTRK(A_UNIT),d3
  2066.     bsr    SeekZero
  2067.     bsr    SelectDrive
  2068.     bsr    SeekNoUpdate
  2069.     bra    .End
  2070.  
  2071. DecodeLong:
  2072. ;A2 - ptr to buffer -- updated
  2073. ;D2 - $55555555
  2074. ;D0 - result
  2075.  
  2076.     move.l    d1,-(sp)
  2077.     move.l    (a2)+,d0
  2078.     move.l    (a2)+,d1
  2079.     and.l    d2,d0
  2080.     and.l    d2,d1
  2081.     add.l    d0,d0    ;was lsl.l #1,d0
  2082.     or.l    d1,d0
  2083.     move.l    (sp)+,d1
  2084.     rts
  2085.  
  2086. EncodeLong:
  2087. ;Enter with data to be encoded in D0.L
  2088. ;and pointer to destination in A0 -- updated
  2089. ;Exit with checksum in D5
  2090.  
  2091.     movem.l    d0-d4,-(sp)
  2092.     moveq    #0,d5
  2093.     move.l    #$55555555,d4
  2094.     move.l    d0,d3
  2095.     lsr.l    #1,d0
  2096.     bsr    Encode
  2097.     move.l    d3,d0
  2098.     bsr    Encode
  2099.     and.l    #$55555555,d5
  2100.     movem.l    (sp)+,d0-d4
  2101.     rts
  2102.  
  2103. Encode:
  2104. ;Enter with longword to code in D0.L and #$55555555 in D4
  2105. ;uses d0,d1,d2,a0 -- not saved
  2106.  
  2107. ;Accumulates checksum in D5
  2108.  
  2109.     and.l    d4,d0
  2110.     move.l    d0,d2
  2111.     eor.l    d4,d2
  2112.     move.l    d2,d1
  2113.     add.l    d2,d2
  2114.     lsr.l    #1,d1
  2115.     bset    #31,d1
  2116.     and.l    d2,d1
  2117.     or.l    d1,d0
  2118.     btst    #0,-1(a0)
  2119.     beq    .ok
  2120.     bclr    #31,d0
  2121. .ok:    eor.l    d0,d5
  2122.     move.l    d0,(a0)+
  2123.     rts
  2124.  
  2125. EncodeBlock:
  2126. ;Destination is always chip RAM (RawBuffer).
  2127. ;Source could be in chip RAM or fast RAM (in A2).
  2128.  
  2129.     movem.l    d0-d1/a0-a1/a6,-(sp)
  2130.     move.l    4,a6
  2131.     move.l    a2,a1
  2132.     SYS    TypeOfMem
  2133.     and.l    #MEMF_CHIP,d0
  2134.     bne    .Chip
  2135.     movem.l    (sp)+,d0-d1/a0-a1/a6
  2136.     bra    EncodeBlockCPU
  2137. .Chip:    movem.l    (sp)+,d0-d1/a0-a1/a6
  2138.     bra    EncodeBlockBlit
  2139.  
  2140. EncodeBlockCPU:
  2141. ;Enter with pointer to source data in A2 -- updated
  2142. ;Enter with pointer to destination in A0 -- updated
  2143.  
  2144. ;Exit with checksum in D5
  2145.     move.l    d6,-(sp)
  2146.     moveq    #0,d5
  2147.     move.w    #(512/4)-1,d6
  2148.  
  2149. EncodeBlockSub:
  2150. ;Number of longwords to encode (minus one) in D6.w
  2151.     movem.l    d0-d4,-(sp)
  2152.  
  2153. ;Encode odd bits
  2154.     push    a2
  2155.     move.w    d6,d3
  2156.     move.l    #$55555555,d4
  2157. .L1:    move.l    (a2)+,d0
  2158.     lsr.l    #1,d0
  2159.     bsr    Encode
  2160.     dbra    d3,.L1
  2161.  
  2162. ;Encode even bits
  2163.     pop    a2
  2164.     move.w    d6,d3
  2165. .L2:    move.l    (a2)+,d0
  2166.     bsr    Encode
  2167.     dbra    d3,.L2
  2168.     and.l    #$55555555,d5
  2169.     movem.l    (sp)+,d0-d4
  2170.     move.l    (sp)+,d6
  2171.     rts
  2172.  
  2173. EncodeSectorLabels:
  2174. ;D5 (checksum) must be initialized by caller
  2175.     move.l    d6,-(sp)
  2176.     move.w    #(16/4)-1,d6
  2177.     bra    EncodeBlockSub
  2178.  
  2179. EncodeBlockBlit:
  2180. ;Enter with pointer to source data in A2 -- updated
  2181. ;Enter with pointer to destination in A0 -- updated
  2182.  
  2183. ;Exit with checksum in D5
  2184.  
  2185.     movem.l    d0-d2/a0-a1/a6,-(sp)
  2186.     push    a0
  2187.     move.l    GraphBase(A_DEVICE),a6
  2188.     SYS    OwnBlitter
  2189.     move.l    (sp),a0
  2190.     move.l    #_custom,a1
  2191.  
  2192.     move.w    #$808,d0    ;BLTSIZE
  2193.  
  2194.     SYS    WaitBlit
  2195.  
  2196.     move.w    #$ffff,bltafwm(a1)
  2197.     move.w    #$ffff,bltalwm(a1)
  2198.     clr.w    bltbmod(a1)
  2199.     clr.w    bltamod(a1)
  2200.     clr.w    bltdmod(a1)
  2201.     move.w    #$5555,bltcdat(a1)
  2202.  
  2203.     move.l    a2,bltbpt(a1)
  2204.     move.l    a2,bltapt(a1)
  2205.     move.l    a0,bltdpt(a1)
  2206.     move.w    #$1db1,bltcon0(a1)
  2207.     clr.w    bltcon1(a1)
  2208.     move.w    d0,bltsize(a1)
  2209.  
  2210.     SYS    WaitBlit
  2211.  
  2212.     move.l    a0,bltbpt(a1)
  2213.     move.l    a2,bltapt(a1)
  2214.     move.l    a0,bltdpt(a1)
  2215.     move.w    #$2d8c,bltcon0(a1)
  2216.     move.w    d0,bltsize(a1)
  2217.     movem.l    a0/a2,-(sp)
  2218.     lea    510(a2),a2    ;ptr to end of src
  2219.     lea    1022(a0),a0
  2220.  
  2221.     SYS    WaitBlit
  2222.  
  2223.     move.l    a2,bltbpt(a1)    ;src end
  2224.     move.l    a2,bltapt(a1)    ;src end
  2225.     move.l    a0,bltdpt(a1)    ;dst end
  2226.     move.w    #$0db1,bltcon0(a1)
  2227.     move.w    #$1002,bltcon1(a1)    ;decrement
  2228.     move.w    d0,bltsize(a1)
  2229.     movem.l    (sp)+,a0/a2
  2230.     lea    512(a0),a0
  2231.  
  2232.     SYS    WaitBlit
  2233.  
  2234.     move.l    a0,bltbpt(a1)
  2235.     move.l    a2,bltapt(a1)
  2236.     move.l    a0,bltdpt(a1)
  2237.     move.w    #$1d8c,bltcon0(a1)
  2238.     clr.w    bltcon1(a1)
  2239.     move.w    d0,bltsize(a1)
  2240.     pop    a0
  2241.  
  2242.     SYS    WaitBlit
  2243.  
  2244.     bsr    Correct
  2245.     lea    512(a0),a0
  2246.     bsr    Correct
  2247.     lea    -512(a0),a0
  2248.  
  2249.     move.w    #(1024/4)-1,d0
  2250.     move.l    #$55555555,d2
  2251.     moveq    #0,d5
  2252. ..    move.l    (a0)+,d1
  2253.     eor.l    d1,d5
  2254.     dbra    d0,..
  2255.     and.l    d2,d5
  2256.  
  2257.     SYS    DisownBlitter
  2258.     movem.l    (sp)+,d0-d2/a0-a1/a6
  2259.     lea    512(a2),a2    ;update source pointer
  2260.     lea    1024(a0),a0    ;update destination pointer
  2261.     rts
  2262.  
  2263. ;This routine corrects the high bit of the current byte based on the
  2264. ;low bit of the previous byte.
  2265.  
  2266. Correct:
  2267.     push    d0
  2268.     move.b    (a0),d0
  2269.     btst    #0,-1(a0)
  2270.     bne    .ResetClock
  2271.     btst    #6,d0
  2272.     bne    .end
  2273.     bset    #7,d0
  2274.     bra    .end1
  2275. .ResetClock:
  2276.     bclr    #7,d0
  2277. .end1:    move.b    d0,(a0)
  2278. .end:    pop    d0
  2279.     rts
  2280.  
  2281. DISK_Wait:
  2282. ;Assumes $dff000 in A6.
  2283.     movem.l    d0-d1,-(sp)
  2284.     tst.w    SyncCount(A_DEVICE)
  2285.     bmi    .OK    ;if WaitWordSync detected a BlockSig, don't wait!
  2286.     move.l    BlockSig(A_DEVICE),d0
  2287.     move.l    #300*1000*2,d1
  2288.     bsr    TimeOutWait
  2289.     bne    .OK
  2290.     moveq    #DISK_NoSync,d7
  2291. .OK:    move.w    #INTF_DSKBLK+INTF_DSKSYNC,intena(a6)    ;disable ints
  2292.     bsr    ClearSigs
  2293.     movem.l    (sp)+,d0-d1
  2294.     rts
  2295.  
  2296. EncodeAndWriteTrack:
  2297. ;Enter with pointer to source data in A2
  2298.  
  2299.     movem.l    d0-d6/a0-a2,-(sp)
  2300.  
  2301.     btst    #CIAB_DSKPROT,ciaapra    ;check write protect status
  2302.     beq    .Protected
  2303.  
  2304.     move.l    RawBuffer(A_DEVICE),a0
  2305.  
  2306. ;Gap = 1660 bytes - 2 bytes for hardware bug
  2307.     move.l    #$aaaaaaaa,d1    ;10101010...
  2308.     move.w    GapCount(A_UNIT),d0    ;414/829
  2309. ..    move.l    d1,(a0)+
  2310.     dbra    d0,..
  2311.     subq.l    #2,a0    ;leave room for 2 extra bytes at the very end
  2312.  
  2313.     move.l    SectorsPerTrack(A_UNIT),d1    ;number of sectors
  2314.     moveq    #0,d3    ;sector count
  2315. .SecLoop:
  2316.     move.l    #$aaaaaaaa,(a0)
  2317.     bsr    Correct
  2318.     addq.l    #4,a0
  2319.     move.l    #$44894489,(a0)+
  2320.     move.l    #$ff000000,d0
  2321.     moveq    #0,d6
  2322.     move.w    TDU_CURRTRK(A_UNIT),d6
  2323.     swap    d6
  2324.     or.l    d6,d0
  2325.     move.l    d3,d6
  2326.     lsl.l    #8,d6
  2327.     or.l    d6,d0
  2328.     or.l    d1,d0
  2329.     bsr    EncodeLong    ;header
  2330.  
  2331. ;Encode sector label
  2332.     push    a2
  2333.     lea    SectorLabels(A_DEVICE),a2
  2334.     move.l    d3,d0
  2335.     lsl.l    #4,d0    ;sector*16
  2336.     lea    (a2,d0.w),a2
  2337.     bsr    EncodeSectorLabels
  2338.     pop    a2
  2339.  
  2340.     move.l    d5,d0
  2341.     bsr    EncodeLong    ;header checksum
  2342.     move.l    a0,d2    ;save raw data pointer
  2343.     addq.l    #8,a0
  2344.     bsr    EncodeBlock    ;encode data block
  2345.     move.l    d5,d0
  2346.     exg    a0,d2
  2347.     bsr    EncodeLong    ;data block checksum
  2348.     bsr    Correct
  2349.     move.l    d2,a0
  2350.     addq.l    #1,d3
  2351.     subq.l    #1,d1
  2352.     bne    .SecLoop
  2353.  
  2354.     move.w    #$aaa8,(a0)
  2355.     bsr    Correct    ;extra word to avoid hardware bug
  2356.  
  2357. ;Physically write the data
  2358. .WriteAgain:
  2359.     bsr    SetRegs
  2360.     bsr    PreComp
  2361.     move.w    #ADKF_WORDSYNC,adkcon(a6)    ;turn OFF wordsync!!!
  2362.     move.w    #$0123,dsksync(a6)
  2363.     bsr    ClearSigs
  2364.     move.w    VerifyDskLen(A_UNIT),BlockIntDskLen(A_DEVICE)
  2365.  
  2366.     btst    #TDPB_VERIFY,TDU_PUBFLAGS(A_UNIT)
  2367.     beq    .SkipVerify
  2368.     bset    #DEVB_Verify,DEV_FLAGS(A_DEVICE)
  2369. .SkipVerify:
  2370.  
  2371.     move.l    VerifyBuffer(A_DEVICE),a0
  2372.     clr.l    (a0)+
  2373.     clr.l    (a0)
  2374.     move.w    #0,dsklen(a6)
  2375.     move.w    WriteDskLen(A_UNIT),dsklen(a6)
  2376.     move.w    WriteDskLen(A_UNIT),dsklen(a6)
  2377.  
  2378. ;This piece of code (commented out) tests the function of the rare
  2379. ;"interrupt delayed" requester. (I've never seen it appear in actual use).
  2380.     comment |
  2381. ;TEST
  2382.     push    a6
  2383.     move.l    4,a6
  2384.     SYS    Disable
  2385.     move.w    #5000,d0
  2386. .L1:    move.b    vhposr+_custom,d1
  2387. .L2:    cmp.b    vhposr+_custom,d1
  2388.     beq    .L2
  2389.     dbra    d0,.L1
  2390.     SYS    Enable
  2391.     pop    a6
  2392. |
  2393.  
  2394.     btst    #TDPB_VERIFY,TDU_PUBFLAGS(A_UNIT)
  2395.     beq    .NoVerify
  2396.  
  2397. ;VERIFY
  2398.  
  2399. ;We verify by comparing the raw MFM data in RawBuffer (what we just wrote)
  2400. ;and VerifyBuffer (what is coming in). Due to the ingenious method of
  2401. ;verifying (thanks to Sebastiano Vigna!) the data comes in sector-by-sector
  2402. ;in the same order that we wrote it.
  2403.  
  2404.     move.l    VerifyBuffer(A_DEVICE),a0
  2405.     move.l    RawBuffer(A_DEVICE),a2
  2406.     add.w    FirstSector(A_UNIT),a2    ;1666/3326 - first sector minus sync
  2407.     bsr    WaitWordSync
  2408.     tst.l    d7
  2409.     bne    .VerifyError
  2410.     bsr    WaitWordSync
  2411.     tst.l    d7
  2412.     bne    .VerifyError
  2413. ;Now we have our first sector in the verify buffer. Scan for a
  2414. ;sync mark. (There may be 1 or 2 sync marks).
  2415.     cmp.w    #$4489,(a0)+
  2416.     bne    .VerifyError
  2417.     cmp.w    #$4489,(a0)
  2418.     bne    .HaveSync
  2419.     addq.l    #2,a0
  2420. .HaveSync:
  2421.  
  2422. ;We go through a rather elaborate procedure here to make sure that we've
  2423. ;started reading with sector 0. (If not, display a requester informing the
  2424. ;user that something is locking out level-1 interrupts for a long period of
  2425. ;time).
  2426.     push    a2
  2427.     move.l    #$55555555,d2
  2428.     move.l    a0,a2
  2429.     bsr    DecodeLong
  2430.     pop    a2
  2431.     and.w    #$ff00,d0
  2432.     beq    .Sector0
  2433.     move.l    a0,a1
  2434.     moveq    #9,d0
  2435.     moveq    #0,d1
  2436. ..    move.l    (a1)+,d3
  2437.     eor.l    d3,d1
  2438.     dbra    d0,..
  2439.     and.l    d2,d1
  2440.     push    a2
  2441.     move.l    a1,a2
  2442.     bsr    DecodeLong
  2443.     pop    a2
  2444.     cmp.l    d0,d1
  2445.     bne    .VerifyError
  2446.  
  2447. ;Display an informational requester.
  2448.     bsr    StopDMA
  2449.     push    a6
  2450.     move.l    IntBase(A_DEVICE),a6
  2451.     cmp.w    #36,LIB_VERSION(a6)
  2452.     bhi    .KS20
  2453.  
  2454. ;Running under 1.3. Put up a DisplayAlert.
  2455.     moveq    #0,d0    ;alert type (recoverable)
  2456.     lea    .AlertLockOut(pc),a0
  2457.     moveq    #20,d1    ;height
  2458.     SYS    DisplayAlert
  2459.     pop    a6
  2460.     bra    .WriteAgain
  2461.  
  2462. ;Running under 2.0. Put up a EasyRequest.
  2463. .KS20:
  2464.     sub.l    a0,a0
  2465.     sub.l    a2,a2
  2466.     lea    .LockOut(pc),a1
  2467.     SYS    EasyRequestArgs
  2468.     pop    a6
  2469.     bra    .WriteAgain
  2470.  
  2471. ;Note: Probably should compare with the blitter, but this will be fairly
  2472. ;fast.
  2473.  
  2474. .Sector0:
  2475.     move.w    #270-1,d0
  2476. ..    cmp.l    (a0)+,(a2)+
  2477.     dbne    d0,..
  2478.     bne    .VerifyError
  2479.  
  2480. ;Now we are over the initial hump of the first sync mark. The rest of the
  2481. ;compare is even easier.
  2482.     move.l    SectorsPerTrack(A_UNIT),d1
  2483.     subq.l    #3,d1
  2484. .VLoop:    bsr    WaitWordSync
  2485.     tst.l    d7
  2486.     bne    .VerifyError
  2487.     move.w    #272-1,d0
  2488. ..    cmp.l    (a0)+,(a2)+
  2489.     dbne    d0,..
  2490.     bne    .VerifyError
  2491.     dbra    d1,.VLoop
  2492.  
  2493. ;We have one more sector to verify. This time we must wait for "Block
  2494. ;done", rather than another sync.
  2495.  
  2496.     bsr    DISK_Wait
  2497.     tst.l    d7
  2498.     bne    .VerifyError
  2499.     move.w    #272-1,d0
  2500. ..    cmp.l    (a0)+,(a2)+
  2501.     dbne    d0,..
  2502.     bne    .VerifyError
  2503.     bra    .End
  2504.  
  2505. .VerifyError:
  2506.     moveq    #0,d7    ;don't propagate the error to the app
  2507. ;We go here if an error is detected during the verify. We first shut down
  2508. ;the read operation that may be in progress, then put up a requester and let
  2509. ;the user choose whether to retry or abort.
  2510.  
  2511.     bsr    StopDMA    ;stop!!
  2512.     push    a6
  2513.     move.l    IntBase(A_DEVICE),a6
  2514.     cmp.w    #36,LIB_VERSION(a6)
  2515.     bhi    .DoKS20
  2516.  
  2517. ;Running under 1.3. Put up a DisplayAlert.
  2518.     moveq    #0,d0    ;alert type (recoverable)
  2519.     lea    .AlertVError(pc),a0
  2520.     moveq    #20,d1    ;height
  2521.     SYS    DisplayAlert
  2522. ;D0 is set to 'TRUE' if the LEFT button was pressed.
  2523.     pop    a6
  2524.     tst.l    d0
  2525.     bne    .WriteAgain    ;go if left button pressed
  2526.     bra    .End
  2527.  
  2528. ;Running under 2.0. Put up a EasyRequest.
  2529. .DoKS20:    sub.l    a0,a0
  2530.     sub.l    a2,a2
  2531.     lea    .VError(pc),a1
  2532.     push    a3
  2533.     move.w    TDU_CURRTRK(A_UNIT),-(sp)
  2534.     clr.w    -(sp)
  2535.     move.l    sp,a3
  2536.     SYS    EasyRequestArgs
  2537.     addq.l    #4,sp
  2538.     pop    a3
  2539.     pop    a6
  2540.     tst.l    d0
  2541.     bne    .WriteAgain    ;go if left gadget hit
  2542.     bra    .End
  2543. .NoVerify:
  2544.     bsr    DISK_Wait
  2545.     move.l    #4*1000,d0
  2546.     bsr    delay    ;post-write delay
  2547. .End:    movem.l    (sp)+,d0-d6/a0-a2
  2548.     rts
  2549. .Protected:
  2550.     moveq    #DISK_WriteProtected,d7
  2551.     bra    .End
  2552.  
  2553. .AlertVError:
  2554.     dc.w    10    ;x coordinate
  2555.     dc.b    10    ;y coordinate
  2556.     dc.b    '*** VERIFY ERROR !!! ***  Hit LEFT button to RETRY'
  2557.     dc.b    ', or RIGHT button to CANCEL.',0
  2558.     dc.b    0    ;continuation byte
  2559.     even
  2560.  
  2561. .AlertLockOut:
  2562.     dc.w    10    ;x coordinate
  2563.     dc.b    10    ;y coordinate
  2564.     dc.b    'Disk block interrupt delayed by >10ms.'
  2565.     dc.b    '  Press mouse button.',0
  2566.     dc.b    0    ;continuation byte
  2567.     even
  2568.  
  2569. .VError:    dc.l    es_SIZEOF
  2570.     dc.l    0
  2571.     dc.l    .Title
  2572.     dc.l    .MainText
  2573.     dc.l    .GadgetText
  2574. .LockOut:    dc.l    es_SIZEOF
  2575.     dc.l    0
  2576.     dc.l    .Title
  2577.     dc.l    .LockOutTxt
  2578.     dc.l    .Okay
  2579. .LockOutTxt:
  2580.     dc.b    'Disk block interrupt delayed by >10ms caused erroneous'
  2581.     dc.b    ' verify.',0
  2582. .Okay:    dc.b    'If you say so. Try it again!',0
  2583. .Title:    dc.b    'hackdisk.device message',0
  2584. .MainText:
  2585.     dc.b    '*** VERIFY ERROR!!! ***',$a,'Track %ld',0
  2586. .GadgetText:
  2587.     dc.b    'Retry|Cancel',0
  2588.     even
  2589.  
  2590. DISK_Write:
  2591.  
  2592. ;Error code returned in D7, as always.
  2593.  
  2594.     movem.l    d0-d5/a0-a2,-(sp)
  2595.  
  2596.     btst    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  2597.     bne    .ProtError
  2598.  
  2599.     move.l    d0,d5    ;length
  2600.  
  2601. ;The meat of the write routine...
  2602.  
  2603. .WriteLoop:
  2604.     move.l    d1,d3    ;offset
  2605.     divu.w    d6,d3    ;d3.w is track #
  2606.     move.l    d3,d4
  2607.     clr.w    d4
  2608.     swap    d4    ;d4.l is byte offset into track
  2609.     bsr    MinSeek
  2610.     tst.l    d4    ;any offset?
  2611.     bne    .Complex    ;yes
  2612.     cmp.l    d6,d5    ;at least a track left?
  2613.     blo    .Complex    ;no
  2614.     move.l    a0,d0
  2615.     btst    #0,d0    ;word aligned?
  2616.     bne    .Complex    ;no, do it the long way
  2617.     move.l    a0,a2
  2618.     bsr    EncodeAndWriteTrack
  2619.     tst.l    d7
  2620.     bne    .End
  2621.     sub.l    d6,d5    ;update length
  2622.     beq    .End
  2623.     add.l    d6,a0    ;update source pointer
  2624.     add.l    d6,d1    ;update offset
  2625.     bra    .WriteLoop
  2626.  
  2627. .Complex:
  2628.  
  2629. ;This part is somewhat difficult. We check the offset and length parameters
  2630. ;to see whether they're a multiple of 512. If so, we keep track of which
  2631. ;sectors will be written in the buffer. This information is later used by
  2632. ;Update to determine whether a part of the original track must be read in.
  2633. ;(We don't attempt this optimization if the user is writing some odd number
  2634. ;of bytes...This is probably why trackdisk has the limits that it does).
  2635.  
  2636.     tst.l    d5
  2637.     beq    .End    ;nothing left, forget it
  2638.     move.l    d4,d0
  2639.     and.w    #%111111111,d0
  2640.     bne    .NoOpt
  2641.     move.l    d4,d0
  2642.     move.l    d5,d2
  2643.     and.w    #%111111111,d2
  2644.     bne    .NoOpt
  2645.     move.l    d5,d2
  2646.     lsr.l    #8,d0
  2647.     lsr.l    #1,d0    ;get starting sector number
  2648.     lsr.l    #8,d2
  2649.     lsr.l    #1,d2    ;get length in sectors
  2650.     move.l    WriteMap(A_DEVICE),d7
  2651. .OptLoop:    bset    d0,d7
  2652.     addq.b    #1,d0
  2653.     cmp.b    #32,d0
  2654.     beq    .EOpt
  2655.     subq.l    #1,d2
  2656.     bne    .OptLoop
  2657. .EOpt:    move.l    d7,WriteMap(A_DEVICE)
  2658.     moveq    #0,d7
  2659.  
  2660. ;This is normally done by ReadTrackAndDecode.
  2661.     move.b    UnitNum(A_UNIT),BufferDrive(A_DEVICE)
  2662.     move.b    TDU_CURRTRK+1(A_UNIT),BufferTrack(A_DEVICE)
  2663.     bra    .Opt    ;don't read (yet)
  2664.  
  2665. .NoOpt:    push    a0
  2666.     move.l    DecodedBuffer(A_DEVICE),a0
  2667.     bsr    ReadTrackAndDecodeBuffered
  2668.     pop    a0
  2669.     tst.l    d7
  2670.     bne    .End
  2671. .Opt:    move.l    DecodedBuffer(A_DEVICE),a1
  2672.     add.l    d4,a1    ;add byte offset into track
  2673.     sub.l    d6,d4
  2674.     neg.l    d4
  2675.     add.l    d4,d1    ;update offset
  2676.  
  2677. ;D4.L - number of bytes that could be transferred from this track
  2678. ;D5.L - number of bytes left in the entire Read request
  2679.  
  2680.     cmp.l    d5,d4
  2681.     bhs    .FinalWrite
  2682.     sub.l    d4,d5    ;update length
  2683.     move.l    d4,d0
  2684.     bsr    CopyMem
  2685.     add.l    d0,a0    ;update dest pointer
  2686.     bset    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  2687.     bra    .WriteLoop
  2688.  
  2689. .FinalWrite:
  2690.     move.l    d5,d0
  2691.     bsr    CopyMem
  2692.     bset    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  2693. .End:    movem.l    (sp)+,d0-d5/a0-a2
  2694.     rts
  2695. .ProtError:
  2696.     moveq    #DISK_WriteProtected,d7
  2697.     bra    .End
  2698.  
  2699. MotorOff:
  2700. ;MotorOff turns off all drive motors and leaves all drives deselected
  2701.     bsr    Deselect
  2702.     bset    #CIAB_DSKMOTOR,ciabprb    ;motor off
  2703.     and.b    #~(CIAF_DSKSEL0+CIAF_DSKSEL1+CIAF_DSKSEL2+CIAF_DSKSEL3),ciabprb    ;select all drives
  2704.     bsr    Deselect
  2705.     clr.b    MotorState(A_DEVICE)
  2706.     rts
  2707.  
  2708. Inquire:
  2709.     IFND    _LVOGetUnitID
  2710. _LVOGetUnitID    equ    -30
  2711.     ENDC
  2712.     movem.l    d0-d2/a0-a1/a6,-(sp)
  2713.     moveq    #0,d2
  2714.     move.l    DiskResourceBase(A_DEVICE),a6
  2715. .Loop:    move.l    d2,d0
  2716.     SYS    GetUnitID
  2717.     moveq    #-1,d1
  2718.     cmp.l    d0,d1
  2719.     beq    .Next
  2720.     bset    d2,InquireBits(A_DEVICE)
  2721. .Next:    addq.l    #1,d2
  2722.     cmp.w    #MD_NUMUNITS,d2
  2723.     blo    .Loop
  2724.     movem.l    (sp)+,d0-d2/a0-a1/a6
  2725.     rts
  2726.  
  2727. GetDriveType:
  2728.  
  2729. ;Determines type of drive and places the proper code into DriveType(A_UNIT).
  2730. ;One of: DRIVE3_5, DRIVE5_25, DRIVE3_5_150RPM
  2731.  
  2732. ;See the Hardware Reference Manual, Appendix E for a description of
  2733. ;the procedure.
  2734.  
  2735. ;Note: Drive zero is always present. In fact, the identification 
  2736. ;scheme does not work with drive zero (except for the half-speed drive).
  2737.  
  2738. ;Warning! Leaves drive deselected!
  2739.  
  2740.     movem.l    d0-d1/d3-d5/a0-a2/a6,-(sp)
  2741.     move.b    UnitNum(A_UNIT),d3
  2742.     addq.b    #3,d3
  2743.     moveq    #7,d1
  2744.     move.l    #ciabprb,a0
  2745.     bsr    Deselect
  2746.     moveq    #31,d4
  2747.     moveq    #0,d5    ;identification longword
  2748.  
  2749.     bclr    d1,(a0)    ;motor on
  2750.     bset    d3,(a0)    ;deselect drive
  2751.     bclr    d3,(a0)    ;select drive
  2752.  
  2753.     bset    d1,(a0)    ;motor off
  2754.     bset    d3,(a0)    ;deselect drive
  2755.     bclr    d3,(a0)    ;select drive
  2756.     bset    d3,(a0)    ;deselect drive
  2757.  
  2758. .ReadIdent:
  2759.     bclr    d3,(a0)    ;select drive
  2760.     btst    #5,ciaapra    ;test ready
  2761.     beq    .zero
  2762.     bset    d4,d5
  2763. .zero:    bset    d3,(a0)    ;deselect drive
  2764.     dbra    d4,.ReadIdent
  2765.  
  2766. ;D5 contains the drive ID.
  2767.     lea    DriveParams(A_UNIT),a0
  2768.     move.w    #(DriveParams_Sizeof/2)-1,d0
  2769. ..    clr.w    (a0)+
  2770.     dbra    d0,..
  2771.     lea    HDParams(pc),a1
  2772.     cmp.l    #DRT_150RPM,d5
  2773.     beq    .DoInitStruct
  2774.     lea    LDParams(pc),a1
  2775. ;    cmp.l    #DRT_AMIGA,d5
  2776.     tst.l    d5
  2777.     beq    .DoInitStruct
  2778.     moveq    #-1,d0
  2779.     cmp.l    d0,d5
  2780.     beq    .DoInitStruct
  2781.     lea    OldParams(pc),a1    ;5.25 inch drive
  2782. .DoInitStruct:
  2783.     moveq    #0,d0    ;area to clear
  2784.     move.l    A_UNIT,a2
  2785.     move.l    4,a6
  2786.     SYS    InitStruct
  2787. .End:    movem.l    (sp)+,d0-d1/d3-d5/a0-a2/a6
  2788.     rts
  2789.  
  2790.  
  2791. SeekZeroAll:
  2792.     movem.l    d0-d2/A_UNIT,-(sp)
  2793.     move.b    InquireBits(A_DEVICE),d0
  2794.     lea    Unit0(A_DEVICE),A_UNIT
  2795.     moveq    #0,d1
  2796.     moveq    #MD_NUMUNITS-1,d2
  2797. .Loop:    btst    d1,d0
  2798.     beq    .Next
  2799.     bsr    SeekZero
  2800. .Next:    lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  2801.     addq.b    #1,d1
  2802.     dbra    d2,.Loop
  2803.     movem.l    (sp)+,d0-d2/A_UNIT
  2804.     rts
  2805.  
  2806. SeekZero:
  2807. ;Places the drive in UnitNum(A_UNIT) on track zero.
  2808. ;Drive does not need to be selected in advance.
  2809. ;Drive will be left _deselected_!
  2810.  
  2811.     movem.l    d0-d1,-(sp)
  2812.  
  2813. .StepLoop:
  2814.     bsr    SelectDriveSameMotor
  2815.     bset    #CIAB_DSKDIREC,ciabprb    ;set to "out" (lower tracks)
  2816.     btst    #CIAB_DSKTRACK0,ciaapra    ;check track zero flag
  2817.     beq    .EndStepLoop
  2818.     bset    #CIAB_DSKSTEP,ciabprb
  2819.     bclr    #CIAB_DSKSTEP,ciabprb    ;step head
  2820.     bset    #CIAB_DSKSTEP,ciabprb
  2821.     bsr    Deselect
  2822.     move.l    TDU_CALIBRATEDELAY(A_UNIT),d0
  2823.     bsr    delay
  2824.     bra    .StepLoop
  2825.  
  2826. .EndStepLoop:
  2827.     bsr    Deselect
  2828.     move.l    TDU_SETTLEDELAY(A_UNIT),d0
  2829.     bsr    delay
  2830.     clr.w    TDU_CURRTRK(A_UNIT)
  2831.     movem.l    (sp)+,d0-d1
  2832.     rts
  2833.  
  2834. CopyMemSlow:
  2835. ;Only to be called by CopyMem
  2836.     move.l    4,a6
  2837.     SYS    CopyMem
  2838.     movem.l    (sp)+,d0-d7/a0-a6
  2839.     rts
  2840.  
  2841. CopyMem:
  2842.  
  2843. ;A0 - source
  2844. ;A1 - destination
  2845. ;D0 - size
  2846.  
  2847.     movem.l    d0-d7/a0-a6,-(sp)
  2848.  
  2849.     move.l    a0,d1
  2850.     btst    #0,d1
  2851.     bne    CopyMemSlow
  2852.     move.l    a1,d1
  2853.     btst    #0,d1
  2854.     bne    CopyMemSlow
  2855.  
  2856.  
  2857. .More:    cmp.l    #512,d0
  2858.     blo    CopyMemSlow
  2859.  
  2860. ;Copy 480 bytes
  2861. n    set    0
  2862.     REPT    10
  2863.     movem.l    (a0)+,d1-d7/a2-a6
  2864.     movem.l    d1-d7/a2-a6,n*48(a1)
  2865. n    set    n+1
  2866.     ENDR
  2867. ;Copy 32 bytes
  2868.     movem.l    (a0)+,d1-d7/a2
  2869.     movem.l    d1-d7/a2,480(a1)
  2870.     lea    512(a1),a1
  2871.     sub.l    #512,d0
  2872.     bne    .More
  2873.     movem.l    (sp)+,d0-d7/a0-a6
  2874.     rts
  2875.  
  2876. LDParams:
  2877.     INITWORD    TDU_COMP10TRACK,-1
  2878.     INITWORD    TDU_COMP11TRACK,-1
  2879.     INITWORD    TDU_COMP01TRACK,80
  2880.     INITLONG    TDU_STEPDELAY,3*1000
  2881.     INITLONG    TDU_SETTLEDELAY,15*1000
  2882.     INITLONG    TDU_CALIBRATEDELAY,4*1000
  2883.  
  2884.     INITBYTE    NumTracks,160
  2885.     INITBYTE    DriveType,DRIVE3_5
  2886.     INITLONG    BytesPerDisk,901120
  2887.     INITLONG    SectorMask,%11111111111
  2888.     INITWORD    GapCount,414
  2889.     INITLONG    SectorsPerTrack,11
  2890.     INITLONG    RawBufSize,13630
  2891.  
  2892.     INITWORD    FirstSector,1666
  2893.     INITWORD    MaxValidSec,$0a00
  2894.     INITWORD    WriteDskLen,$da9e
  2895.     INITWORD    ReadDskLen,$9a9e
  2896.     INITWORD    VerifyDskLen,$9761
  2897.     dc.w    0
  2898.  
  2899. OldParams:    ;for 5.25 inch drives
  2900.     INITWORD    TDU_COMP10TRACK,-1
  2901.     INITWORD    TDU_COMP11TRACK,-1
  2902.     INITWORD    TDU_COMP01TRACK,80/2
  2903.     INITLONG    TDU_STEPDELAY,3*1000*2
  2904.     INITLONG    TDU_SETTLEDELAY,15*1000*2
  2905.     INITLONG    TDU_CALIBRATEDELAY,4*1000*2
  2906.  
  2907.     INITBYTE    NumTracks,80
  2908.     INITBYTE    DriveType,DRIVE5_25
  2909.     INITLONG    BytesPerDisk,901120/2
  2910.     INITLONG    SectorMask,%11111111111
  2911.     INITWORD    GapCount,414
  2912.     INITLONG    SectorsPerTrack,11
  2913.     INITLONG    RawBufSize,13630
  2914.  
  2915.     INITWORD    FirstSector,1666
  2916.     INITWORD    MaxValidSec,$0a00
  2917.     INITWORD    WriteDskLen,$da9e
  2918.     INITWORD    ReadDskLen,$9a9e
  2919.     INITWORD    VerifyDskLen,$9761
  2920.     dc.w    0
  2921.  
  2922. HDParams:
  2923.     INITWORD    TDU_COMP10TRACK,-1
  2924.     INITWORD    TDU_COMP11TRACK,-1
  2925.     INITWORD    TDU_COMP01TRACK,80
  2926.     INITLONG    TDU_STEPDELAY,3*1000
  2927.     INITLONG    TDU_SETTLEDELAY,15*1000
  2928.     INITLONG    TDU_CALIBRATEDELAY,4*1000
  2929.  
  2930.     INITBYTE    NumTracks,160
  2931.     INITBYTE    DriveType,DRIVE3_5_150RPM
  2932.     INITLONG    BytesPerDisk,901120*2
  2933.     INITLONG    SectorMask,%1111111111111111111111
  2934.     INITWORD    GapCount,829
  2935.     INITLONG    SectorsPerTrack,22
  2936.     INITLONG    RawBufSize,13630*2
  2937.  
  2938.     INITWORD    FirstSector,3326
  2939.     INITWORD    MaxValidSec,$1500
  2940.     INITWORD    WriteDskLen,$f53c
  2941.     INITWORD    ReadDskLen,$b53b
  2942.     INITWORD    VerifyDskLen,$aec1
  2943.     dc.w    0
  2944.  
  2945. EndCode:
  2946.  
  2947. ;************************* Northgate fix *********************************
  2948.  
  2949. ;This tiny module performs a keyboard handshake. Its purpose is to wake up a
  2950. ;Northgate keyboard on accelerated systems. If you don't fit that description
  2951. ;then just ignore it. It's harmless.
  2952.  
  2953. NRomTag:    dc.w    RTC_MATCHWORD    ;$4AFC ('illegal' opcode)
  2954.     dc.l    NRomTag
  2955.     dc.l    NEndCode    ;pointer to end of code
  2956.     dc.b    RTF_COLDSTART
  2957.     dc.b    0    ;version
  2958.     dc.b    NT_LIBRARY    ;module type (either device or library)
  2959.     dc.b    0    ;priority
  2960.     dc.l    FixName    ;name
  2961.     dc.l    FixName    ;IDString
  2962.     dc.l    Northgate    ;init routine
  2963. FixName:    dc.b    'Northgate_fix',$a,0
  2964.     even
  2965.  
  2966. Northgate:
  2967. ;Perform a keyboard handshake
  2968.     or.b    #$40,$BFEE01
  2969.     clr.b    $bfec01
  2970.     move.l    #$bfe001,a0
  2971.     move.w    #$46*3,d0
  2972. ..    move.b    (a0),(a0)
  2973.     dbra    d0,..
  2974.     and.b    #$BF,$BFEE01
  2975.     rts
  2976.  
  2977. NEndCode:
  2978.  
  2979. ;*************************** Debugging stuff *************************
  2980.  
  2981.     IFNE    INFO_LEVEL
  2982.  
  2983. KPutFmt:    move.l    a2,-(sp)
  2984.     lea    KPutChar(pc),a2
  2985.     bsr    KDoFmt
  2986.     move.l    (sp)+,a2
  2987.     rts
  2988.  
  2989. KDoFmt:    move.l    a6,-(sp)
  2990.     move.l    4,a6
  2991.     SYS    RawDoFmt
  2992.     move.l    (sp)+,a6
  2993.     rts
  2994.  
  2995. KPutChar:
  2996.  
  2997. ;Serial
  2998.     comment |
  2999.     move.l    a6,-(sp)
  3000.     move.l    4,a6
  3001.     SYS    RawPutChar
  3002.     move.l    (sp)+,a6
  3003.     rts
  3004. |
  3005.  
  3006. ;Printer
  3007.     comment |
  3008.     move.b    #$ff,$bfe301
  3009. .Print:    btst    #0,$bfd000
  3010.     bne    .Print
  3011.     move.b    d0,$bfe101
  3012.     rts
  3013. |
  3014.  
  3015. ;Memory
  3016.     tst.l    MemPtr
  3017.     bne    .OK
  3018.     move.l    #$500000,MemPtr
  3019. .OK:
  3020.     push    a0
  3021.     move.l    MemPtr(pc),a0
  3022.     move.b    d0,(a0)+
  3023.     move.l    a0,MemPtr
  3024.     pop    a0
  3025.     rts
  3026.  
  3027. MemPtr:    dc.l    0
  3028.  
  3029.     ENDC
  3030.